﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

#Область ДляВызоваИзДругихПодсистем

// Следующие процедуры и функции предназначены для интеграции с 1С-Отчетность
#Область ОбщиеФункции

// Служебная функция для формирования описания сертификата хранящийся на сервере DSS
//
// Возвращаемое значение:
//  Структура:
//    * Идентификатор 		- Число - внутренний идентификатор (код) зарегистрированного сертификата на сервере DSS
//    * Отпечаток 			- Строка - отпечаток сертификата, по которому в последующем производится поиск
//    * ТребуетсяПинКод 		- Булево - признак того, что у сертификата установлен пин-код
//    * ПинКод 				- Строка - хранит пин-код полученный в процессе работы пользователя, ввел вручную или получен из хранилища
//    * Основной 				- Булево - признак сертификата "по-умолчанию" на сервере DSS
//    * Представление 		- Строка - представление сертификата, используемое для отображение пользователю
//    * Содержимое 			- Строка - данные сертификата в формате Base64
//    * ДатаНачала 			- Дата - начало срока действия сертификата
//    * ДатаОкончания 		- Дата - окончание срока действия сертификата
//    * Издатель 				- Строка - представление издателя сертификата
//    * АлгоритмыХеширования 	- Массив - элементы массива содержат описание алгоритма хеширования
//
Функция СвойстваСертификатаПользователя() Экспорт
	
	Результат = Новый Структура();
	Результат.Вставить("Идентификатор", -1);
	Результат.Вставить("Отпечаток", "");
	Результат.Вставить("КомуВыдан", "");
	Результат.Вставить("ТребуетсяПинКод", Истина);
	Результат.Вставить("ПинКод", "");
	Результат.Вставить("Основной", Ложь);
	Результат.Вставить("Представление", "");
	Результат.Вставить("Содержимое", "");
	Результат.Вставить("ДатаНачала", '00010101');
	Результат.Вставить("ДатаОкончания", '00010101');
	Результат.Вставить("Издатель", "");
	Результат.Вставить("АлгоритмыХеширования", Новый Массив);

	Возврат Результат;
	
КонецФункции

// Возвращает описание сертификата зарегистрированного на сервере DSS.
//	
// Параметры:
//  НастройкиПользователя 	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//  ТекущийСертификат 		- Неопределено - поиск "основного" сертификат, который имеет данный признак на сервере
//                    		- Строка - "Любой", первый попавшийся сертификат
//                    		- Число - поиск по идентификатору сертификата
//                    		- Структура - содержит обязательное поле "Отпечаток", поиск по отпечатку сертификата
//
// Возвращаемое значение:
//   см. СвойстваСертификатаПользователя
//
Функция НайтиСертификат(НастройкиПользователя, ТекущийСертификат) Экспорт
	
	Результат = СвойстваСертификатаПользователя();
	
	ВсеСертификаты = НастройкиПользователя.Сертификаты;
	
	Если ТекущийСертификат = "Любой" Тогда
		ПодобралиСертификат = Неопределено;
		Для каждого СтрокаКлюча Из ВсеСертификаты Цикл
			ТекущийСертификат = СтрокаКлюча.Значение;
			Если ПодобралиСертификат = Неопределено Тогда
				ПодобралиСертификат = ТекущийСертификат;
			ИначеЕсли НЕ СтрокаКлюча.Значение.ТребуетсяПинКод 
				ИЛИ ЗначениеЗаполнено(СтрокаКлюча.Значение.ПинКод) Тогда
				ПодобралиСертификат = СтрокаКлюча.Значение;
			КонецЕсли;	
		КонецЦикла;
		
		Если ПодобралиСертификат <> Неопределено Тогда
			Результат = ПодобралиСертификат;
		КонецЕсли;
	
	ИначеЕсли ТекущийСертификат = Неопределено Тогда
		Для каждого СтрокаКлюча Из ВсеСертификаты Цикл
			Если СтрокаКлюча.Значение.Основной ИЛИ ВсеСертификаты.Количество() = 1 Тогда
				Результат = СтрокаКлюча.Значение;
				Прервать;
			КонецЕсли;	
		КонецЦикла;
		
	ИначеЕсли ТипЗнч(ТекущийСертификат) = Тип("Число") Тогда
		Для каждого СтрокаКлюча Из НастройкиПользователя.Сертификаты Цикл
			Если СтрокаКлюча.Значение.Идентификатор = ТекущийСертификат Тогда
				Результат = СтрокаКлюча.Значение;
				Прервать;
			КонецЕсли;	
		КонецЦикла;
		
	ИначеЕсли ТипЗнч(ТекущийСертификат) = Тип("Структура") Тогда
		Отпечаток = ПолучитьПолеСтруктуры(ТекущийСертификат, "Отпечаток", "---");
		Отпечаток = НРег(Отпечаток);
		Для каждого СтрокаКлюча Из ВсеСертификаты Цикл
			Если СтрокаКлюча.Значение.Отпечаток = Отпечаток Тогда
				Результат = СтрокаКлюча.Значение;
				Прервать;
			КонецЕсли;	
		КонецЦикла;
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Служебная функция для поиска и получения значения в сложнопостроенной среде: Структура, Соответствие, Массив (по индексу).
//
// Параметры:
//  ДанныеСтруктуры 		- Структура, Соответствие, Массив - допускает сочетание
//  ПутьДанных	 			- Строка - полный путь в дереве
//  ЗначениеПоУмолчанию 	- Произвольный - возвращает значение, если не найдено в дереве, по умолчанию Неопределено
//  УчитыватьРегистр 		- Булево - учитывать регистр ключей при поиске
//
// Возвращаемое значение:
//  Произвольный - значение полученное по указанному пути
//
// Пример:
//	ВторичныйМетод	= СервисКриптографииDSSСлужебный.ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.TextChallenge[0].AuthnMethod", ""),
//	ВторичныйМетод	= СервисКриптографииDSSСлужебный.ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.TextChallenge['Fff fdf'], "").
//
Функция ПолучитьПолеСтруктуры(ДанныеСтруктуры, Знач ПутьДанных, ЗначениеПоУмолчанию = Неопределено, УчитыватьРегистр = Ложь) Экспорт
	
	Если ДанныеСтруктуры = Неопределено Тогда
		Возврат ЗначениеПоУмолчанию;
	КонецЕсли;
	
	СпецСимвол 				= "~";
	ПутьДанных				= СтрЗаменить(ПутьДанных, "['", СпецСимвол);
	ПутьДанных				= СтрЗаменить(ПутьДанных, "'].", СпецСимвол);
	ПутьДанных				= СтрЗаменить(ПутьДанных, "']", СпецСимвол);
	ПутьДанных				= СтрЗаменить(ПутьДанных, "[", СпецСимвол);
	ПутьДанных				= СтрЗаменить(ПутьДанных, "].", СпецСимвол);
	ПутьДанных				= СтрЗаменить(ПутьДанных, "]", СпецСимвол);
	ПутьДанных				= СтрЗаменить(ПутьДанных, "'", СпецСимвол);
	ПутьДанных				= СтрЗаменить(ПутьДанных, ".", СпецСимвол);
	
	ПоследовательностьПолей = СтрРазделить(ПутьДанных, СпецСимвол, Ложь);
	Результат				= ЗначениеПоУмолчанию;
	СледующееПоле			= ДанныеСтруктуры;
	
	Для каждого СтрокаМассива Из ПоследовательностьПолей Цикл
		НашлиПоле = Неопределено;
		Если ТипЗнч(СледующееПоле) = Тип("Массив")
			ИЛИ ТипЗнч(СледующееПоле) = Тип("ФиксированныйМассив") Тогда
			Если ЭтоЦелоеЧисло(СтрокаМассива) Тогда
				ИндексПоля = Число(СтрокаМассива);
				Если СледующееПоле.Количество() > ИндексПоля И ИндексПоля >= 0 Тогда
					НашлиПоле = СледующееПоле.Получить(ИндексПоля);
				КонецЕсли;	
			КонецЕсли;	
			СледующееПоле = НашлиПоле;
			
		ИначеЕсли ТипЗнч(СледующееПоле) = Тип("Соответствие")
			ИЛИ ТипЗнч(СледующееПоле) = Тип("ФиксированноеСоответствие") Тогда
			Если УчитыватьРегистр Тогда
				НашлиПоле = СледующееПоле.Получить(СтрокаМассива);
			Иначе	
				Для каждого СтрокаКлюча Из СледующееПоле Цикл
					Если НРег(СтрокаКлюча.Ключ) = НРег(СтрокаМассива) Тогда
						НашлиПоле = СтрокаКлюча.Значение;
						Прервать;
					КонецЕсли;	
				КонецЦикла;
			КонецЕсли;	
			СледующееПоле = НашлиПоле;
			
		ИначеЕсли (ТипЗнч(СледующееПоле) = Тип("Структура")
			ИЛИ ТипЗнч(СледующееПоле) = Тип("ФиксированнаяСтруктура")
			ИЛИ ТипЗнч(СледующееПоле) = Тип("ДанныеФормыСтруктура"))
			И ЭтоИмяПеременной(СтрокаМассива) Тогда
			СледующееПоле.Свойство(СтрокаМассива, СледующееПоле);
			
		Иначе
			СледующееПоле = Неопределено;
			
		КонецЕсли;
		
		Если СледующееПоле = Неопределено Тогда
			Прервать;
		КонецЕсли;
		
	КонецЦикла;
	
	Если СледующееПоле <> Неопределено Тогда
		Результат = СледующееПоле;
	КонецЕсли;
	
	Если ЗначениеПоУмолчанию <> Неопределено
		И ТипЗнч(Результат) <> ТипЗнч(ЗначениеПоУмолчанию) Тогда
		МассивТипа	= Новый Массив;
		МассивТипа.Добавить(ТипЗнч(ЗначениеПоУмолчанию));
		ТипЗначения = Новый ОписаниеТипов(МассивТипа);
		Результат = ТипЗначения.ПривестиЗначение(Результат);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Служебная функция для формирования представления номера телефона. 
// В данном представлении частично скрывается информация по шаблону: 8911*****11.
//
// Параметры: 
//  ТекущийТелефон - Строка - номер телефона
//
// Возвращаемое значение:
//  Строка - представление номера телефона без части цифр
//
Функция ПредставлениеТелефона(ТекущийТелефон) Экспорт
	
	Результат	= СокрЛП(ТекущийТелефон);
	Счетчик 	= СтрДлина(Результат);
	ВсегоЦифр	= 0;
	
	Пока Счетчик > 0 Цикл
		ЭтоЦифра = СтрНайти("0123456789", Сред(Результат, Счетчик, 1))  > 0;
		Если ЭтоЦифра Тогда
			ВсегоЦифр = ВсегоЦифр + 1;
		КонецЕсли;
		
		Если ВсегоЦифр > 2 И ЭтоЦифра Тогда
			Результат = Сред(Результат, 1, Счетчик - 1) + "*" + Сред(Результат, Счетчик + 1);
		КонецЕсли;
		
		Если ВсегоЦифр >= 7 Тогда
			Прервать;
		КонецЕсли;
		
		Счетчик 	= Счетчик - 1;
		
	КонецЦикла;	
	
	Возврат Результат;
	
КонецФункции

// Служебная функция для формирования представления адреса электронной почты. 
// В данном представлении частично скрывается информация по шаблону "q**r.ru".
//
// Параметры: 
//  ТекущийАдрес - Строка - адрес электронной почты
//
// Возвращаемое значение:
//  Строка - представление адреса электронной почты без части информации
//
Функция ПредставлениеАдресаПочты(ТекущийАдрес) Экспорт
	
	Результат	= СокрЛП(ТекущийАдрес);
	Позиция		= СтрНайти(ТекущийАдрес, "@");
	Если Позиция > 0 Тогда
		ПерваяЧасть = Сред(ТекущийАдрес, 1, Позиция - 1);
		ДлинаЧасти	= СтрДлина(ПерваяЧасть);
		Если ДлинаЧасти > 2 Тогда
			Результат 	= Сред(ПерваяЧасть, 1, 1) + Прав("**********", ДлинаЧасти - 2) + Сред(Результат, Позиция - 1, 1) + Сред(Результат, Позиция);
		КонецЕсли;	
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Служебная функция для конвертирования отпечатка из двоичного или строки Base64 представления в HEX
// 
// Параметры:
//  ОтпечатокСертификата - ДвоичныеДанные, Строка - значение отпечатка
//
// Возвращаемое значение:
//   Строка - HEX представление отпечатка без пробелов
//
Функция ТрансформироватьОтпечаток(ОтпечатокСертификата) Экспорт
	
	Если ТипЗнч(ОтпечатокСертификата) = Тип("ДвоичныеДанные") Тогда
		Результат = ПолучитьHexСтрокуИзДвоичныхДанных(ОтпечатокСертификата);
	Иначе	
		Результат = ПолучитьHexСтрокуИзДвоичныхДанных(Base64Значение(ОтпечатокСертификата));
	КонецЕсли;	
	
	Возврат Результат;
	
КонецФункции

// Служебная функция для анализа наличия конфиденциальных данных.
// 
// Параметры:
//  ТекущиеДанные	- Неопределено - данные введены, но не видны
//               	- Строка - в открытом виде
//               	- Структура - подробнее ОбъектПароля 
//
// Возвращаемое значение:
//   Булево - введены конфиденциальные данные
//
Функция ТребуетсяВводКонфиденциальныхДанных(ТекущиеДанные) Экспорт
	
	Результат = Истина;
	
	Если ТипЗнч(ТекущиеДанные) = Тип("Структура") Тогда
		Результат = ТекущиеДанные.Состояние = 3;
		
	ИначеЕсли ТекущиеДанные = Неопределено Тогда
		Результат = Ложь;
		
	Иначе
		Результат = НЕ ЗначениеЗаполнено(ТекущиеДанные);
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Формирует структуру с описанием пароля.
// 
//	Параметры:
//    ЗначениеПароля	- Строка - текущее значение
//    СостояниеПароля	- Число - описывает состояние значения пароля
//						0 - представлен в открытом виде,
//						1 - представлен в закрытом виде,
//						2 - установлен, хранится в сеансовых данных и значение пустое,
//						3 - не заполнен,
//						4 - пустой пароль,
//						5 - идентификатор пароля, представленный в закрытом виде.
//    Признак			- Число - алгоритм закрытия 
//    ИсточникНастроек	- Строка
//                    	- Неопределено
//
// Возвращаемое значение:
//  Структура:
//    * Значение 		- Строка
//    * Состояние		- Число
//    * Признак		- Число - алгоритм закрытия 
//
Функция ОбъектПароля(ЗначениеПароля, СостояниеПароля = 0, Признак = 1, ИсточникНастроек = Неопределено) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Признак", Признак);
	Результат.Вставить("Состояние", СостояниеПароля);
	Если СостояниеПароля = 5 Тогда
		Результат.Вставить("Значение", СокрЛП(Новый УникальныйИдентификатор));
		СервисКриптографииDSSСлужебныйВызовСервера.УстановитьЗначениеПараметраСессии(Результат.Значение, ЗначениеПароля, ИсточникНастроек);
	Иначе
		Результат.Вставить("Значение", Строка(ЗначениеПароля));
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Формирует структуру с описанием пароля.
//	Параметры:
//    ЗначениеПароля				- Строка, Структура - открытое значение пароля, см. также см. СервисКриптографииDSSКлиентСервер.ОбъектПароля
//    АвторизованныйПользователь	- СправочникСсылка.Пользователи, Строка - ссылка на текущего пользователя
//    Признак						- Число - алгоритм закрытия 
//    ИсточникНастроек				- Строка
//                    				- Неопределено
//
// Возвращаемое значение:
//   см. СервисКриптографииDSSКлиентСервер.ОбъектПароля
//
Функция ПодготовитьОбъектПароля(ЗначениеПароля, АвторизованныйПользователь, Признак = 1, ИсточникНастроек = Неопределено) Экспорт
	
	Если ТипЗнч(ЗначениеПароля) = Тип("Структура") Тогда
		Результат = ЗначениеПароля;
		Если ЗначениеПароля.Состояние = 0 И ЗначениеЗаполнено(ЗначениеПароля.Значение) Тогда
			Результат = ОбъектПароля(ЗакрытьСекретПользователя(ЗначениеПароля.Значение, АвторизованныйПользователь, Признак), 1, , ИсточникНастроек);
		КонецЕсли;	
		
	ИначеЕсли ЗначениеПароля = Неопределено Тогда
		Результат = ОбъектПароля(ЗначениеПароля, 3, , ИсточникНастроек);
		
	ИначеЕсли НЕ ЗначениеЗаполнено(ЗначениеПароля) Тогда
		Результат = ОбъектПароля(ЗначениеПароля, 4, , ИсточникНастроек);
		
	ИначеЕсли ЗначениеЗаполнено(Признак) Тогда
		Результат = ОбъектПароля(ЗакрытьСекретПользователя(ЗначениеПароля, АвторизованныйПользователь, Признак), 1, ИсточникНастроек);
		
	Иначе
		Результат = ОбъектПароля(ЗначениеПароля, 0, , ИсточникНастроек);
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Извлекает текстовое представление пароля из объекта
// 
// Параметры:
//  ОбъектПароля 				- Строка, Структура - см. СервисКриптографииDSSКлиентСервер.ОбъектПароля
//  АвторизованныйПользователь  - Строка, 
//                              - СправочникСсылка.Пользователи
//
// Возвращаемое значение:
//  Строка
//
Функция ПолучитьЗначениеПароля(ОбъектПароля, АвторизованныйПользователь) Экспорт
	
	Если ТипЗнч(ОбъектПароля) = Тип("Структура") Тогда
		
		Если ОбъектПароля.Состояние = 0 Тогда
			Результат = ЗакрытьСекретПользователя(ОбъектПароля.Значение, АвторизованныйПользователь);
		ИначеЕсли ОбъектПароля.Состояние = 1 Тогда
			Результат = ОбъектПароля.Значение;
		Иначе
			Результат = "";
		КонецЕсли;
		
	Иначе
		Результат = Строка(ОбъектПароля);
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Функция определения актуальности данных аутентификации учетной записи облачной подписи
// 
// Параметры:
//  НастройкиПользователя - см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//  ДатаСеанса - Дата - дата и время на стороне потребителя в универсальном виде
//
// Возвращаемое значение:
//   Булево - Истина, если аутентификация актуальна
//
Функция УчетнаяЗаписьАвторизована(НастройкиПользователя, ДатаСеанса) Экспорт
	
	Результат = Ложь;
	
	Если НастройкиПользователя.Политика.Заполнено Тогда
		Если НастройкиПользователя.ТокенАвторизации.СрокДействия >= ДатаСеанса Тогда
			Результат = Истина;
		ИначеЕсли НЕ ТребуетсяВводКонфиденциальныхДанных(НастройкиПользователя.ТокенАвторизации.ТокенОбновления) Тогда
			Результат = Истина;
		ИначеЕсли НастройкиПользователя.ЗапоминатьПароли Тогда
			Результат = Истина;
		КонецЕсли;
	КонецЕсли;	
		
	Возврат Результат;
	
КонецФункции

// Определяет режим обязательного подтверждения выполняемой операции.
// см. СвойствоВыполняемойОперации()  
//
// Параметры:
//  НастройкиПользователя 	- Структура, СправочникСсылка.УчетныеЗаписиDSS - данные учетной записи облачной подписи
//  ВидОперации 			- Строка - вид выполняемой операции
//
// Возвращаемое значение:
//  Булево
//
Функция ТребуетсяПодтверждениеОперации(НастройкиПользователя, ВидОперации = "") Экспорт
	
	КлючДействия = СвойствоВыполняемойОперации(НастройкиПользователя, ВидОперации);
	
	Результат = КлючДействия.Подтверждать;
	
	Возврат Результат;
	
КонецФункции	

// Определяет описание свойство выполняемой операции.
// Такими операциями могут быть: ПодписьПакета, ПодписьДокумента, Расшифрование, ЗапросНаСертификат, СменаПинКода 
// и т.д.  
//
// Параметры:
//  НастройкиПользователя 	- Структура, СправочникСсылка.УчетныеЗаписиDSS - данные учетной записи облачной подписи
//  ВидОперации 			- Строка - вид выполняемой операции
//  ПараметрыОперации	 	- Структура, ФиксированнаяСтруктура - позволяет указать дополнительные параметры операции.
//
// Возвращаемое значение:
//  Булево
//
Функция СвойствоВыполняемойОперации(НастройкиПользователя, ВидОперации = "", ПараметрыОперации = Неопределено) Экспорт
	
	ЗначениеПоУмолчанию = Новый Структура("КодОперации, Подтверждать", 0, Ложь);
	
	Если ТипЗнч(НастройкиПользователя) = Тип("СправочникСсылка.УчетныеЗаписиDSS") Тогда
		ТекущиеНастройки = СервисКриптографииDSSСлужебныйВызовСервера.ПолучитьНастройкиПользователя(НастройкиПользователя, ПараметрыОперации);
	Иначе
		ТекущиеНастройки = НастройкиПользователя;
	КонецЕсли;	
	
	Результат = ПолучитьПолеСтруктуры(ТекущиеНастройки, "Политика.Действия." + ВидОперации, ЗначениеПоУмолчанию);
	
	Возврат Результат;
	
КонецФункции

// Возвращает описание типа для справочника учетных записей облачной подписи
//
// Возвращаемое значение:
//  Тип 
//
Функция ПолучитьТипОблачнойПодписи() Экспорт
	
	Результат = Тип("СправочникСсылка.УчетныеЗаписиDSS");
	
	Возврат Результат;
	
КонецФункции

// Возвращает описание типа для справочника серверов облачной подписи
//
// Возвращаемое значение:
//  Тип 
//
Функция ПолучитьТипСервераОблачнойПодписи() Экспорт
	
	Результат = Тип("СправочникСсылка.ЭкземплярыСервераDSS");
	
	Возврат Результат;
	
КонецФункции

// Определяет идентификатор алгоритма закрытого ключ на основе его имени.
//
// Параметры:
//  ИмяАлгоритма - Строка
//
// Возвращаемое значение:
//  Строка - строковое представление идентификатора (число) алгоритма
//
Функция ИдентификаторАлгоритмаЗакрытогоКлюча(ИмяАлгоритма) Экспорт
	
	ВсеАлгоритмы = Новый Соответствие();
	
	ВсеАлгоритмы.Вставить("CALG_GR3410EL", "11811"); // Идентификатор алгоритма ЭЦП по ГОСТ Р 34.10-2001
	ВсеАлгоритмы.Вставить("GOST R 34.10-2001", "11811"); // Альтернативное имя алгоритма
	ВсеАлгоритмы.Вставить("CALG_DH_EL_SF", "43556"); // Идентификатор алгоритма обмена ключей по алгоритму DH на базе закрытого ключа пользователя. Открытый ключ получается по ГОСТ Р 34.10 2001.
	ВсеАлгоритмы.Вставить("CALG_DH_EL_EPHEM", "43557"); // Идентификатор алгоритма обмена ключей по алгоритму DH на базе закрытого ключа эфемерной пары. Открытый ключ получается по ГОСТ Р 34.10 2001.
	
	ВсеАлгоритмы.Вставить("CALG_GR3410_12_256", "11849"); // Идентификатор алгоритма ЭЦП по ГОСТ Р 34.10-2012 (256 бит).
	ВсеАлгоритмы.Вставить("GOST R 34.10-2012-256", "11849"); // Альтернативное имя алгоритма
	ВсеАлгоритмы.Вставить("CALG_DH_GR3410_12_256_SF", "43590"); // Идентификатор алгоритма обмена ключей по алгоритму DH на базе закрытого ключа пользователя. Открытый ключ получается по ГОСТ Р 34.10 2012 (256 бит).
	
	ВсеАлгоритмы.Вставить("CALG_GR3410_12_512", "11837"); // Идентификатор алгоритма ЭЦП по ГОСТ Р 34.10-2012 (512 бит).
	ВсеАлгоритмы.Вставить("GOST R 34.10-2012-512", "11837"); // Альтернативное имя алгоритма
	ВсеАлгоритмы.Вставить("CALG_DH_GR3410_12_512_SF", "43586"); // Идентификатор алгоритма обмена ключей по алгоритму DH на базе закрытого ключа пользователя. Открытый ключ получается по ГОСТ Р 34.10 2012 (512 бит).
	
	ВсеАлгоритмы.Вставить("CALG_RSA_KEYX", "41984"); // Идентификатор алгоритм обмена открытыми ключами RSA.
	ВсеАлгоритмы.Вставить("CALG_RSA_SIGN", "9216"); // Идентификатор алгоритма ЭЦП RSA.

	Результат = ВсеАлгоритмы[ИмяАлгоритма];
	Если Результат = Неопределено Тогда
		Результат = ИмяАлгоритма;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Формирует массив поддерживаемых версий в АПИ БСП
//
// Возвращаемое значение:
//  Массив из Строка - содержит список строк с версиями
//
Функция ПоддерживаемыеВерсии() Экспорт
	
	Результат = Новый Массив;
	Результат.Добавить("2.0.2882");
	Результат.Добавить("2.0.3284");
	
	Возврат Результат;
	
КонецФункции	

// Проверяет логин (имя учетной записи) на допустимые символы
//
// Параметры:
//  ЛогинПользователя 	- Строка
//
// Возвращаемое значение:
//  Структура:
//    * Выполнено 	- Булево
//    * Ошибка		- Строка - представления для формирования форматированной строки, в случае если Выполнено Ложь
//
Функция ПроверитьКорректностьЛогина(ЛогинПользователя) Экспорт
	
	Результат = Новый Структура("Выполнено", Истина);
	
	ПредставлениеОшибки = "";
	ШаблонОшибки = "<span style=""background-color: ПоясняющийОшибкуТекст"">%1</span>";
	Запрещенные = Новый Массив;
	Запрещенные.Добавить(" ");
	
	Для Счетчик = 1 По СтрДлина(ЛогинПользователя) Цикл
		ТекущийСимвол = Сред(ЛогинПользователя, Счетчик, 1);
		Если Запрещенные.Найти(ТекущийСимвол) = Неопределено Тогда
			ПредставлениеОшибки = ПредставлениеОшибки + ТекущийСимвол;
		Иначе
			Результат.Выполнено = Ложь;
			ПредставлениеОшибки = ПредставлениеОшибки + СтрШаблон(ШаблонОшибки, ТекущийСимвол);
		КонецЕсли;	
	КонецЦикла;	
	
	Если НЕ Результат.Выполнено Тогда
		Результат.Вставить("Ошибка", ПредставлениеОшибки);
	КонецЕсли;	
	
	Возврат Результат;
	
КонецФункции

#КонецОбласти

#Область ФормированиеСвойствПодписи

// Таблица для получения кодов и наименований типов подписей, в различных комбинациях
//
// Возвращаемое значение:
//  Соответствие из КлючИЗначение:
//    * Ключ 		- Строка, Число - строковый или числовой идентификатор
//    * Значение 	- Строка, Число - строковый или числовой идентификатор
//
Функция ПолучитьТипыПодписей() Экспорт
	
	Результат = Новый Соответствие;
	Результат.Вставить("XML", 0);
	Результат.Вставить("ГОСТ", 1);
	Результат.Вставить("CMS", 5);
	Результат.Вставить("CAdES", 2);
	Результат.Вставить("PDF", 3);
	Результат.Вставить("MSOffice", 4);
	
	Результат.Вставить("XMLDSig", 0);
	Результат.Вставить("GOST3410", 1);
	
	Результат.Вставить(0, "XML");
	Результат.Вставить(1, "ГОСТ");
	Результат.Вставить(5, "CMS");
	Результат.Вставить(2, "CAdES");
	Результат.Вставить(3, "PDF");
	Результат.Вставить(4, "MSOffice");
	
	Возврат Результат;
	
КонецФункции

// Формирует список документов для представления в формах подтверждения
// Параметры: 
//  ДанныеДокументов 	- Массив - содержит элементы из структур с описанием документов
//                   	- Структура - содержит описание документа
// 
// Возвращаемое значение:
//   Структура:
//     * СписокДокументов - Массив из Структура
//
Функция ПодготовитьНаборДокументов(ДанныеДокументов) Экспорт
	
	Результат			= Новый Структура("СписокДокументов", Новый Массив);
	
	Если ТипЗнч(ДанныеДокументов) = Тип("Структура") Тогда
		Результат.СписокДокументов.Добавить(ДанныеДокументов);
		
	ИначеЕсли ТипЗнч(ДанныеДокументов) = Тип("Массив") Тогда
		Для каждого СтрокаМассива Из ДанныеДокументов Цикл
			Результат.СписокДокументов.Добавить(СтрокаМассива);
		КонецЦикла;
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Формирует параметры запроса в случае пакетной подписи документов
// Передается массив документов каждый элемент массива это структура, поля которой содержит 
// адрес во временном хранилище, двоичные данные или Base64.
//
// Параметры: 
//  МассивДокументов - Массив - содержит элементы из структур:
//    * Содержание 			- ДвоичныеДанные, Строка - двоичные данные, адрес во временном хранилище или Base64
//    * ИмяДокумента 			- Строка - имя документа 
//    * ТипДокумента 			- Строка - расширение документа, используется для правильного отображения в мобильном приложении
//    * ИсходноеСодержание 	- ДвоичныеДанные, Строка - содержимое исходного документа, используется в режиме "СоПодпись"
//
// Возвращаемое значение:
//   Массив из Структура:
//    * Content 			- Строка - Base64
//    * Name 				- Строка - имя файла или описание файла
//    * Type 				- Строка - расширение файла, как было передано из входящих данных
//    * OriginalContent 	- Строка - Base64
//    * ВернутьКак 		- см. ПодготовитьДанныеДокумента
//
Функция ПодготовитьПакетДляПодписи(МассивДокументов) Экспорт
	
	Результат = Новый Массив;
	
	Для каждого СтрокаМассива Из МассивДокументов Цикл
		
		НоваяСтрока = Новый Структура();
		НоваяСтрока.Вставить("Content", "");
		НоваяСтрока.Вставить("ContentInfo", "");
		НоваяСтрока.Вставить("Name", "");
		НоваяСтрока.Вставить("Type", "");
		НоваяСтрока.Вставить("OriginalContent", "");
		НоваяСтрока.Вставить("RefId", "");
		НоваяСтрока.Вставить("ВернутьКак", "");
		
		Если ТипЗнч(СтрокаМассива) = Тип("Структура") Тогда
			СтруктураДокумента = ПодготовитьДанныеДокумента(СтрокаМассива.Содержание);
			НоваяСтрока.Name = СтрокаМассива.ИмяДокумента;
			НоваяСтрока.ContentInfo = СтрокаМассива.ИмяДокумента + "." + СтрокаМассива.ТипДокумента;
			Если СтруктураДокумента.ТипДокумента = "ИдентификаторХранилища" Тогда
				НоваяСтрока.RefId = СтрокаМассива.Содержание;
			Иначе
				НоваяСтрока.Content = СтруктураДокумента.Документ;
			КонецЕсли;
			НоваяСтрока.Type = СтрокаМассива.ТипДокумента;
			НоваяСтрока.OriginalContent = СтрокаМассива.ИсходноеСодержание;
			НоваяСтрока.ВернутьКак = СтруктураДокумента.ТипДокумента;
			
		Иначе
			СтруктураДокумента = ПодготовитьДанныеДокумента(СтрокаМассива);
			ИмяФайла = "temp.txt";
			
			Если СтруктураДокумента.ТипДокумента = "ИдентификаторХранилища" Тогда
				НоваяСтрока.RefId = СтрокаМассива;
			Иначе
				НоваяСтрока.Content = СтруктураДокумента.Документ;
				НоваяСтрока.ContentInfo = ИмяФайла;
				НоваяСтрока.ВернутьКак = СтруктураДокумента.ТипДокумента;
			КонецЕсли;
			
		КонецЕсли;
		
		Результат.Добавить(НоваяСтрока);
		
	КонецЦикла;	
	
	Возврат Результат;
	
КонецФункции

// Базовая функция для формирования структуры описание для операции подписи документа.
// Строит структуру параметров с учетом применения в режиме транзакции.
// Вызывается для окончательного формирования структуры из функций:
//	ПолучитьСвойствоПодписиГост(),
//	ПолучитьСвойствоПодписиCMS(),
//	ПолучитьСвойствоПодписиXML(),
//	ПолучитьСвойствоПодписиCAdES(),
//	ПолучитьСвойствоПодписиPDF(),
// 	ПолучитьСвойствоПодписиMSOffice().
// В случае вызова сервиса без транзакции, происходит трансформация структуры в СервисКриптографииDSS.Подписать.
//
// Параметры:
//  ТипПодписи 			- Строка - строковый идентификатор типа подписи: ГОСТ, XML, CAdES, PDF, MSOffice 
//  ПараметрыПодписи 	- Структура - структура которые сформированы заранее в выше описанных функциях
//
// Возвращаемое значение:
//  Структура - содержит поля, необходимые для формирования запроса к сервису в зависимости от типа подписи
// 
Функция ПолучитьОписаниеПодписи(ТипПодписи, ПараметрыПодписи = Неопределено) Экспорт
	
	Результат = Новый Структура();
	
	Если ПараметрыПодписи = Неопределено Тогда
		ПараметрыПодписи = Новый Структура;
	КонецЕсли;
	
	ДополнительныеПараметры = Новый Структура;
	
	Если ТипПодписи = "ГОСТ" Тогда
		Результат.Вставить("SignatureType", "GOST3410");
		ДополнительныеПараметры.Вставить("Hash", "false");
		
	ИначеЕсли ТипПодписи = "XML" Тогда
		Результат.Вставить("SignatureType", "XMLDSig");
		ДополнительныеПараметры.Вставить("XMLDSigType", "XMLEnveloped");
		
	ИначеЕсли ТипПодписи = "CAdES" Тогда
		Результат.Вставить("SignatureType", "CAdES");
		ДополнительныеПараметры.Вставить("IsDetached", "false");
		ДополнительныеПараметры.Вставить("CADESType", "XLT1");
		Если ПараметрыПодписи.Свойство("CmsSignatureType") Тогда
			ДополнительныеПараметры.Вставить("CmsSignatureType", "sign");
			Если ПараметрыПодписи.CmsSignatureType = "cosign" Тогда
				ДополнительныеПараметры.Вставить("OriginalDocument", "");
			КонецЕсли;	
		КонецЕсли;
		Если ПараметрыПодписи.Свойство("ContentEncoding") Тогда
			ДополнительныеПараметры.Вставить("ContentEncoding", "base64");
		КонецЕсли;
		Если ПараметрыПодписи.Свойство("Hash") Тогда
			ДополнительныеПараметры.Вставить("Hash", "false");
		КонецЕсли;	
		Если ПараметрыПодписи.Свойство("CmsSignatureType") Тогда
			ДополнительныеПараметры.Вставить("CmsSignatureType", "sign");
		КонецЕсли;	
		Если ПараметрыПодписи.Свойство("TSPAddress") Тогда
			ДополнительныеПараметры.Вставить("TSPAddress", "");
		КонецЕсли;	
		
	ИначеЕсли ТипПодписи = "PDF" Тогда
		Результат.Вставить("SignatureType", "PDF");
		ДополнительныеПараметры.Вставить("PDFFormat", "CMS");
		ДополнительныеПараметры.Вставить("PDFReason", "test");// обязательно
		ДополнительныеПараметры.Вставить("PDFLocation", "temp");// обязательно
		
	ИначеЕсли ТипПодписи = "MSOffice" Тогда
		Результат.Вставить("SignatureType", "MSOffice");
		
	КонецЕсли;
	
	ВсеТипы		= ПолучитьТипыПодписей();
	Результат.Вставить("SignatureType", ВсеТипы[ТипПодписи]);
	
	ЗаполнитьЗначенияСвойств(ДополнительныеПараметры, ПараметрыПодписи);
	
	Для каждого СтрокаКлюча Из ДополнительныеПараметры Цикл
		Результат.Вставить(СтрокаКлюча.Ключ, СтрокаКлюча.Значение);
	КонецЦикла;	
	
	Возврат Результат;
	
КонецФункции

// Сервисная функция для формирования параметров запроса к сервису для подписи документа в формате ГОСТ.
//
// Параметры:
//  ХешДокумента - Булево - Истина, если формируется подпись для хеша документа, в данных документа в этом случае
//                          передается Хеш документа.
//	
// Возвращаемое значение:
//   см. ПолучитьОписаниеПодписи
//
Функция ПолучитьСвойствоПодписиГост(ХешДокумента = Ложь) Экспорт
	
	Дополнение = Новый Структура("Hash", ?(ХешДокумента, "True", "False"));
	Результат = ПолучитьОписаниеПодписи("ГОСТ", Дополнение);
	Возврат Результат;
	
КонецФункции

// Сервисная функция для формирования параметров запроса к сервису для подписи документа в формате CMS.
// Как частный вариант реализации для CAdES-BES подписи, подробнее в ПолучитьСвойствоПодписиCAdES.
//
// Параметры:
//  ОтделеннаяПодпись 	- Булево - Истина, если формируется отделенная подпись
//  ХешДокумента 		- Булево - подпись хеша документа, в данных документа передается хеш документа
//  ВариантПодписи 		- Строка - варианты: "Подпись", "СоПодпись", "Заверяющая"
//  ИсходныйДокумент 	- ДвоичныеДанные
//  ИндексПодписи 		- Число - индекс подписи, которую заверяем
//	
// Возвращаемое значение:
//   см. ПолучитьОписаниеПодписи
//
Функция ПолучитьСвойствоПодписиCMS(ОтделеннаяПодпись,
							ХешДокумента,
							ВариантПодписи = "Подпись",
							ИсходныйДокумент = Неопределено,
							ИндексПодписи = Неопределено) Экспорт
							
	ВсеТипы	= ПолучитьТипыПодписей();
	Результат = ПолучитьСвойствоПодписиCAdES("BES", ОтделеннаяПодпись, ХешДокумента, ВариантПодписи, "", ИсходныйДокумент);
	Результат.Вставить("SignatureType", ВсеТипы["CMS"]);
	
	Возврат Результат;
	
КонецФункции

// Сервисная функция для формирования параметров запроса к сервису для подписи документа в формате XML.
//
// Параметры:
//  ВариантПодписи - Строка - содержит возможные варианты:
//	 					Шаблон (XMLTemplate) - подготовленный специальным образом документ, в этом случае данные для подписания включены в шаблон
//						Включенная (XMLEnveloped) - включена в исходный документ отдельным узлом
//						Содержащая (XMLEnveloping) - содержит в себе исходный документ в виде включенного узла.
//	
// Возвращаемое значение:
//   см. ПолучитьОписаниеПодписи
//
Функция ПолучитьСвойствоПодписиXML(ВариантПодписи = "") Экспорт
	
	Дополнение = Новый Структура;
	
	Если ВариантПодписи = "Шаблон" Тогда
		Дополнение.Вставить("XMLDSigType", "XMLTemplate");
	ИначеЕсли ВариантПодписи = "Включенная" Тогда
		Дополнение.Вставить("XMLDSigType", "XMLEnveloped");
	Иначе
		Дополнение.Вставить("XMLDSigType", "XMLEnveloping");
	КонецЕсли;
	
	Результат = ПолучитьОписаниеПодписи("XML", Дополнение);
	
	Возврат Результат;
	
КонецФункции

// Сервисная функция для формирования параметров запроса к сервису для подписи документа в формате CAdES
//
// Параметры:
//  ТипПодписи 			- Строка - содержит варианты: XLT1 (CAdES-X Long Type 1), T (CAdES-T), BES (CAdES-BES)
//  ОтделеннаяПодпись 	- Булево - Истина, если формируется отделенная подпись
//  ХешДокумента 		- Булево - подпись хеша документа, в данных документа передается хеш документа
//  ВариантПодписи 		- Строка - варианты: "Подпись", "СоПодпись", "Заверяющая"
//  АдресTSPСлужбы 		- Строка - адрес службы штампов времени (TSP или OCSP службы), для ТипПодписи Т и XLT1 
//						зарегистрированный адрес можно узнать в политике настроек пользователя.
//  ИсходныйДокумент 	- ДвоичныеДанные - передается для режима подписи: "СоПодпись" (Base64) в пакетном режиме игнорируется.
//  ИндексПодписи 		- Число - индекс подписи, для которой создается заверяющая подпись
//	
// Возвращаемое значение:
//   см. ПолучитьОписаниеПодписи
//
Функция ПолучитьСвойствоПодписиCAdES(
							ТипПодписи,
							ОтделеннаяПодпись,
							ХешДокумента,
							ВариантПодписи,
							АдресTSPСлужбы = "",
							ИсходныйДокумент = Неопределено,
							ИндексПодписи = Неопределено) Экспорт
	
	Дополнение = Новый Структура();
	Дополнение.Вставить("IsDetached", ?(ОтделеннаяПодпись, "true", "false"));
	Дополнение.Вставить("CADESType", ТипПодписи);
	Дополнение.Вставить("Hash", ?(ХешДокумента, "true", "false"));
	Дополнение.Вставить("CmsSignatureType", "sign");
	Если ВРег(ВариантПодписи) = "СОПОДПИСЬ" Тогда
		Дополнение.Вставить("CmsSignatureType", "cosign");
		Дополнение.Вставить("OriginalDocument", "ИсходныйДокумент");
	ИначеЕсли ВРег(ВариантПодписи) = "ЗАВЕРЯЮЩАЯ" Тогда
		Дополнение.Вставить("CmsSignatureType", "counterSign");
	КонецЕсли;
	
	Если ТипПодписи = "XLT1" ИЛИ ТипПодписи = "T" Тогда
		Дополнение.Вставить("TSPAddress", АдресTSPСлужбы);
	КонецЕсли;	
	
	Если ЗначениеЗаполнено(ИндексПодписи) Тогда
		Дополнение.Вставить("SignatureIndex", Формат(ИндексПодписи, "ЧГ="));
	КонецЕсли;
	
	Результат 	= ПолучитьОписаниеПодписи("CAdES", Дополнение);
	
	Возврат Результат;
	
КонецФункции

// Сервисная функция для формирования параметров запроса к сервису для подписи документа в формате CMS.
// Как частный вариант реализации для CAdES-BES подписи, подробнее ПолучитьСвойствоПодписиCAdES.
//
// Параметры:
//  ТипПодписи 				- Строка - возможные варианты: CMS (PKCS7), CAdEST, CAdES (CAdES-X Long Type 1)
//  ЦельПодписания 			- Строка - описание цели подписания документа
//  МестоПодписания 		- Строка - описание места подписания документа
//  ШаблонВидимойПодписи 	- Строка - строковое представление шаблона видимой подписи
//  ИдентификаторШаблона 	- Число - 
//								1 - простой текстовый шаблон,
//								2 - шаблон с логотипом и текстом,
//								3 - шаблон в виде изображения.
//  УровеньИзменений 		- Строка - описывает уровень изменения документа после подписания
//								NOT_CERTIFIED - для утверждения,
//								CERTIFIED_NO_CHANGES_ALLOWED - изменения запрещены,
//								CERTIFIED_FORM_FILLING - заполнение полей форм,
//								CERTIFIED_FORM_FILLING_AND_ANNOTATIONS - комментарии и заполнение полей форм.
//	
// Возвращаемое значение:
//   см. ПолучитьОписаниеПодписи
//
Функция ПолучитьСвойствоПодписиPDF(ТипПодписи, ЦельПодписания, МестоПодписания, 
			ШаблонВидимойПодписи = "", 
			ИдентификаторШаблона = 1,
			УровеньИзменений = "") Экспорт
	
	Дополнение = Новый Структура();
	Дополнение.Вставить("PDFFormat", ТипПодписи);
	Дополнение.Вставить("PDFReason", ЦельПодписания);// обязательно
	Дополнение.Вставить("PDFLocation", МестоПодписания);// обязательно
	Если ЗначениеЗаполнено(ШаблонВидимойПодписи) Тогда
		Дополнение.Вставить("PdfSignatureAppearance", ШаблонВидимойПодписи);
	КонецЕсли;
	Если ЗначениеЗаполнено(ИдентификаторШаблона) Тогда
		Дополнение.Вставить("PdfSignatureTemplateId ", Формат(ИдентификаторШаблона, "ЧГ="));
	КонецЕсли;
	Если ЗначениеЗаполнено(УровеньИзменений) Тогда
		Дополнение.Вставить("PDFCertificationLevel", УровеньИзменений);
	КонецЕсли;
	
	Результат = ПолучитьОписаниеПодписи("PDF", Дополнение);
	Возврат Результат;
	
КонецФункции

// Сервисная функция для формирования параметров запроса к сервису для подписи документа в формате MS Office.
// Подписывает новые форматы файлов MS Word и Excel например *.docx.
// При подписывании файла *.doc созданного в MS Word 2003 возникает ошибка.
//
// Возвращаемое значение:
//   см. ПолучитьОписаниеПодписи
//
Функция ПолучитьСвойствоПодписиMSOffice() Экспорт
	
	Дополнение 	= Новый Структура();
	Результат	= ПолучитьОписаниеПодписи("MSOffice", Дополнение);
	
	Возврат Результат;

КонецФункции

// Возвращает реестр серверов штампов времени из настроек авторизованного пользователя DSS.
//
// Параметры:
//  НастройкиПользователя 	- Структура
//                        	- СправочникСсылка.УчетныеЗаписиDSS
//
// Возвращаемое значение:
//   Массив из Структура:
//    * Имя					- Строка - представление сервера
//    * Адрес 				- Строка - адрес службы TSP-сервера
//
Функция ПолучитьСервераШтамповВремени(НастройкиПользователя) Экспорт
	
	Если ТипЗнч(НастройкиПользователя) = Тип("СправочникСсылка.УчетныеЗаписиDSS") Тогда
		ТекущиеНастройки = СервисКриптографииDSSСлужебныйВызовСервера.ПолучитьНастройкиПользователя(НастройкиПользователя);
	Иначе
		ТекущиеНастройки = НастройкиПользователя;
	КонецЕсли;	
	
	Результат = ПолучитьПолеСтруктуры(ТекущиеНастройки, "Политика.СервераШтамповВремени", Новый Массив);
	
	Возврат Результат;
	
КонецФункции

// Сервисная функция для формирования подпись в асинхронном режиме
//
// Параметры:
//  СвойстваПодписи 			- Структура - СервисКриптографииDSSКлиентСервер.ПолучитьСвойствоПодписиГост,
//                  			СервисКриптографииDSSКлиентСервер.ПолучитьСвойствоПодписиCMS,
//                  			СервисКриптографииDSSКлиентСервер.ПолучитьСвойствоПодписиXML,
//                  			СервисКриптографииDSSКлиентСервер.ПолучитьСвойствоПодписиCAdES,
//                  			СервисКриптографииDSSКлиентСервер.ПолучитьСвойствоПодписиPDF,
//                  			СервисКриптографииDSSКлиентСервер.ПолучитьСвойствоПодписиMSOffice.
//  ИдентификаторыДокументов 	- Строка, Массив - идентификатор или идентификаторы документов загруженных на сервер 
//  ИдентификаторПрофиля 		- Строка - идентификатор профиля подписи
//  ИдентификаторыСвязанныхДокументов - Строка, Массив - идентификатор связанного документа загруженных на сервер
//
// Возвращаемое значение:
//   см. ПолучитьОписаниеПодписи
//
Функция ПолучитьСвойствоПодписиАсинхронной(СвойстваПодписи, ИдентификаторыДокументов, ИдентификаторПрофиля = Неопределено, ИдентификаторыСвязанныхДокументов = Неопределено) Экспорт
	
	Подпись = Новый Структура;
	Подпись.Вставить("Type", СвойстваПодписи.SignatureType);
	УдалитьСвойство(СвойстваПодписи, "SignatureType");
	Подпись.Вставить("Parameters", СвойстваПодписи);
	
	Результат = Новый Структура;
	Результат.Вставить("Signature", Подпись);
	
	ДанныеДокументов = ЗначениеВМассиве(ИдентификаторыДокументов);
	
	МассивДокументов = ЗначениеВМассиве(ИдентификаторыСвязанныхДокументов);
	Если ИдентификаторыСвязанныхДокументов = Неопределено Тогда
		МассивДокументов.Очистить();
	КонецЕсли;
	
	Для Счетчик = 0 По МассивДокументов.Количество() - 1 Цикл
		СтрокаМассива = ДанныеДокументов[Счетчик];
		СтрокаМассива.Вставить("RelatedRefId", МассивДокументов[Счетчик]);
	КонецЦикла;
	
	ОписаниеДокумента = ПолучитьПолеСтруктуры(СвойстваПодписи, "DocumentInfo");
	ТипДокумента = ПолучитьПолеСтруктуры(СвойстваПодписи, "DocumentType");
	
	Если ЗначениеЗаполнено(ТипДокумента) 
		И ЗначениеЗаполнено(ОписаниеДокумента) 
		И ДанныеДокументов.Количество() = 1 
		И ДанныеДокументов[0].Свойство("ContentInfo") Тогда
		ДанныеДокументов[0].ContentInfo = ОписаниеДокумента + "." + ТипДокумента;
	КонецЕсли;
	
	// дополняем текущую структуру информацией о документах
	Результат.Вставить("BinaryData", ДанныеДокументов);
	Если ЗначениеЗаполнено(ИдентификаторПрофиля) Тогда
		Результат.Вставить("ProcessingTemplateId", ИдентификаторПрофиля);
	КонецЕсли;	
	
	УдалитьСвойство(СвойстваПодписи, "DocumentInfo");
	УдалитьСвойство(СвойстваПодписи, "DocumentType");
	
	Возврат Результат;
	
КонецФункции


// Формирует атрибуты для проверки отсоединенной подписи и хеш значения
//
// Параметры:
//  АлгоритмХеш - Строка - один из вариантов
//		GOST R 34.11-94,
//		GR 34.11-2012 256,
//		GR 34.11-2012 512,
//		SHA-1,
//		SHA-256,
//		SHA-384,
//		SHA-512,
//		MD5.
//  СодержимоеPKCS7 - Булево - признак, что содержимое документа это PKCS7
//  СодержимоеХеш	- Булево - Истина, если переданные содержать хеш значение
//  НомерПодписи 	- Число - индекс проверяемой подписи, если 0, то проверяются все подписи
//
// Возвращаемое значение:
//  Структура - содержит поля, необходимые для формирования запроса к сервису:
//    * Hash			- Булево 
//    * HashAlgorithm	- Строка
//    * ExtractContent- Булево
//    * VerifyAll		- Булево
//    * SignatureIndex- Число
//    * VerifyPKCS7	- Булево
//
Функция ПолучитьСвойстваПроверкиПодписиХеш(
			АлгоритмХеш, 
			СодержимоеPKCS7 = Истина,
			СодержимоеХеш = Ложь,
			НомерПодписи = 0) Экспорт
					
	Атрибуты = Новый Структура();
	Атрибуты.Вставить("Hash", СодержимоеХеш);
	Атрибуты.Вставить("HashAlgorithm", АлгоритмХеш);
	Атрибуты.Вставить("ExtractContent", Ложь);
	Атрибуты.Вставить("VerifyAll", Ложь);
	
	Если НомерПодписи <> 0 Тогда
		Атрибуты.Вставить("SignatureIndex", НомерПодписи);
	Иначе
		Атрибуты.Вставить("VerifyAll", Истина);
	КонецЕсли;	
	
	Атрибуты.Вставить("VerifyPKCS7", СодержимоеPKCS7);
	
	Возврат Атрибуты;
	
КонецФункции

// Формирует атрибуты для проверки подписи с помощью сервиса.
// Для PDF и XML значение СодержимоеPKCS7 должно быть Ложь.
//
// Параметры:
//  СодержимоеPKCS7	- Булево - указывает, что содержимое представляет собой PKCS7
//  НомерПодписи	- Число - индекс проверяемой подписи, если 0, проверяются все подписи
//
// Возвращаемое значение:
//  Структура - содержит поля, необходимые для формирования запроса к сервису:
//    * VerifyPKCS7		- Булево
//    * ExtractContent 	- Булево
//    * VerifyAll			- Булево
//    * SignatureIndex	- Число
//
Функция ПолучитьСвойстваПроверкиПодписи(
			СодержимоеPKCS7 = Истина,
			НомерПодписи = 0) Экспорт
					
	Атрибуты = Новый Структура();
	Атрибуты.Вставить("VerifyAll", Ложь);
	Если НомерПодписи <> 0 Тогда
		Атрибуты.Вставить("SignatureIndex", НомерПодписи);
	Иначе
		Атрибуты.Вставить("VerifyAll", Истина);
	КонецЕсли;	
		
	Атрибуты.Вставить("VerifyPKCS7", СодержимоеPKCS7);
	Атрибуты.Вставить("ExtractContent", Ложь);
	
	Возврат Атрибуты;
	
КонецФункции

// Служебная процедура дополняет атрибуты проверки подписи информацией о документе, 
// требуется в случае использования режима подтверждения.
//
// Параметры:
//  СвойствоПодписи 		- Структура - сформированная структура с атрибутами для проверки подписи
//  ИнформацияДокумента 	- Строка - описание проверяемого документа
//  ТипДокумента 			- Строка - расширения документа, необходимое для отображения в мобильном приложении
//
Процедура ПолучитьИнформациюДокументаДляПодписи(СвойствоПодписи, ИнформацияДокумента, ТипДокумента) Экспорт
	
	СвойствоПодписи.Вставить("DocumentInfo", ИнформацияДокумента);
	СвойствоПодписи.Вставить("DocumentType", ТипДокумента);
	
КонецПроцедуры

#КонецОбласти

#Область ФормированиеСвойствТранзакций

// Сервисная функция для формирования специфических параметров для вызова сервиса
// в случае использования подтверждения расшифрования.
//
// Параметры:
//  ТипШифрования 				- Строка - значение из двух вариантов: CMS или XML
//  ИдентификаторСертификата 	- Число - внутренний идентификатор сертификата
//  ТипДокумента 				- Строка - расширение документа, которые может использоваться для определения алгоритма отображения на мобильном устройстве
//  ИнформацияОДокументе 		- Строка - описание документа
//
// Возвращаемое значение:
//  Массив из Структура:
//    * Name	- Строка - имя поля
//    * Value	- Строка - значение поля
//
Функция СвойстваТранзакцииРасшифрования(
			ТипШифрования,
			ИдентификаторСертификата,
			ТипДокумента = "",
			ИнформацияОДокументе = "") Экспорт
			
	ДанныеЗапроса 	= Новый Массив;
	НоваяСтрока		= Новый Структура("Name, Value", "EncryptionType", ТипШифрования);
	ДанныеЗапроса.Добавить(НоваяСтрока);
	НоваяСтрока		= Новый Структура("Name, Value", "CertificateID", Формат(ИдентификаторСертификата, "ЧГ="));
	ДанныеЗапроса.Добавить(НоваяСтрока);
	НоваяСтрока		= Новый Структура("Name, Value", "DocumentInfo", ИнформацияОДокументе);
	ДанныеЗапроса.Добавить(НоваяСтрока);
	НоваяСтрока		= Новый Структура("Name, Value", "DocumentType", ТипДокумента);
	ДанныеЗапроса.Добавить(НоваяСтрока);
	
	Возврат ДанныеЗапроса;
	
КонецФункции

// Сервисная функция для формирования специфических параметров для вызова сервиса
// в случае использования подтверждения подписания.
//
// Параметры:
//  СвойстваПодписи 			- Структура - содержит поля, которые сформированы в блоке "ФормированиеСвойствПодписи"
//  ИдентификаторСертификата 	- Число - внутренний идентификатор сертификата
//
// Возвращаемое значение:
//  Массив из Структура:
//    * Name	- Строка - имя поля
//    * Value	- Строка - значение поля
//
Функция СвойстваТранзакцииПодписания(СвойстваПодписи, ИдентификаторСертификата) Экспорт
			
	ДанныеЗапроса 	= Новый Массив;
	Для каждого СтрокаКлюча Из СвойстваПодписи Цикл
		НоваяСтрока		= Новый Структура("Name, Value", СтрокаКлюча.Ключ, СтрокаКлюча.Значение);
		ДанныеЗапроса.Добавить(НоваяСтрока);
	КонецЦикла;
	
	НоваяСтрока		= Новый Структура("Name, Value", "CertificateID", ИдентификаторСертификата);
	ДанныеЗапроса.Добавить(НоваяСтрока);
	
	Возврат ДанныеЗапроса;
	
КонецФункции

// Сервисная функция для формирования специфических параметров для вызова сервиса
// в случае использования подтверждения смены пин-код сертификата.
//
// Параметры:
//  ИдентификаторСертификата - Число - внутренний идентификатор сертификата
//
// Возвращаемое значение:
//  Массив из Структура - в данном случает состоит из одного элемента:
//    * Name	- Строка - имя поля
//    * Value	- Строка - значение поля
//
Функция СвойстваТранзакцииСменыПинКода(ИдентификаторСертификата = 0) Экспорт
			
	ДанныеЗапроса 	= Новый Массив;
	НоваяСтрока		= Новый Структура("Name, Value", "CertificateID", Формат(ИдентификаторСертификата, "ЧГ="));
	ДанныеЗапроса.Добавить(НоваяСтрока);
	
	Возврат ДанныеЗапроса;
	
КонецФункции

// Сервисная функция для формирования специфических параметров для вызова сервиса
// в случае использования подтверждения запроса на новый сертификат.
//
// Параметры:
//  ИдентификаторУЦ 		- Число - внутренний идентификатор УЦ
//  ИдентификаторШаблона 	- Строка - OID шаблона запроса
//  ИмяСертификата 			- Строка - имя сертификата, suject name
//
// Возвращаемое значение:
//  Массив из Структура - в данном случает состоит из одного элемента:
//    * Name	- Строка - имя поля
//    * Value- Строка - значение поля
//
Функция СвойстваТранзакцииЗапросНаСертификат(ИдентификаторУЦ,
							ИдентификаторШаблона,
							ИмяСертификата) Экспорт
			
	ДанныеЗапроса 	= Новый Массив;
	НоваяСтрока		= Новый Структура("Name, Value", "CAId", Формат(ИдентификаторУЦ, "ЧГ="));
	ДанныеЗапроса.Добавить(НоваяСтрока);
	НоваяСтрока		= Новый Структура("Name, Value", "CertSubjectName", ИмяСертификата);
	ДанныеЗапроса.Добавить(НоваяСтрока);
	НоваяСтрока		= Новый Структура("Name, Value", "CertTemplateOid", Формат(ИдентификаторШаблона, "ЧГ="));
	ДанныеЗапроса.Добавить(НоваяСтрока);
	
	Возврат ДанныеЗапроса;
	
КонецФункции

#КонецОбласти

#Область ФормированиеСвойствДокумента

// Формирует структуру с описанием свойств документа, предназначенного для загрузки на сервер.
//
// Параметры:
//    ИмяФайла 			- Строка - имя файла
//    ТипФайла			- Строка - тип формата документа
//    ВременныйФайл		- Булево - регистрировать документ как временный
//    ИдРодителя			- Строка - идентификатор родительского документа
//    МаленькийФайл 		- Булево - признак, что файл маленький
//    ШаблонДокумента 	- Строка - содержимое шаблона документа
//    ШаблонКонвертации 	- Строка - содержимое шаблона конвертации документа
//
// Возвращаемое значение:
//  Структура - содержит поля, необходимые для формирование запроса к серверу:
//    * FileName - Строка
//    * FileType - Строка
//    * ParentDocumentId - Строка
//    * IsTemporary - Булево
//    * AdditionalInfo - Структура:
//      ** DocumentTemplate - Строка
//      ** SnippetTemplate - Строка
//      ** SmallFile - Булево
//
Функция ПолучитьСвойстваДокумента(
		ИмяФайла,
		ТипФайла,
		ВременныйФайл,
		ИдРодителя,
		МаленькийФайл = Неопределено,
		ШаблонДокумента = "",
		ШаблонКонвертации = "") Экспорт
		
	Результат = Новый Структура;
	
	Если ЗначениеЗаполнено(ИмяФайла) Тогда
		Результат.Вставить("FileName", ИмяФайла);
	Иначе	
		Результат.Вставить("FileName", "Temp.txt");
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ТипФайла) Тогда
		Результат.Вставить("FileType", ТипФайла);
	Иначе	
		Результат.Вставить("FileType", "txt");
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ИдРодителя) Тогда
		Результат.Вставить("ParentDocumentId", ИдРодителя);
	КонецЕсли;
	
	Результат.Вставить("IsTemporary", ВременныйФайл);
	
	ДополнительнаяИнформация = Новый Структура;
	Если ЗначениеЗаполнено(ШаблонДокумента) Тогда
		ДополнительнаяИнформация.Вставить("DocumentTemplate", ШаблонДокумента);
	Иначе	
		ДополнительнаяИнформация.Вставить("DocumentTemplate", "");
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ШаблонКонвертации) Тогда
		ДополнительнаяИнформация.Вставить("SnippetTemplate", ШаблонКонвертации);
	Иначе	
		ДополнительнаяИнформация.Вставить("SnippetTemplate", "");
	КонецЕсли;
	
	Если МаленькийФайл <> Неопределено Тогда
		ДополнительнаяИнформация.Вставить("SmallFile", МаленькийФайл);
	КонецЕсли;
	
	Результат.Вставить("AdditionalInfo", ДополнительнаяИнформация);
	
	Возврат Результат;
	
КонецФункции

// Дополняет свойства документа для загрузки данными самого документа.
// Такой состав свойств документа необходим при выполнении функции СервисКриптографииDSS.ЗагрузитьПакетДокументов.
//
// Параметры:
//  СвойстваДокумента	- см. СервисКриптографииDSSКлиентСервер.ПолучитьСвойстваДокумента
//  СодержимоеДокумента	- ДвоичныеДанные, Строка - один файл, который необходимо обработать,
//					 		подробнее в СервисКриптографииDSSКлиентСервер.ПодготовитьДанныеДокумента().
//	
Процедура ДополнитьСвойстваДокументаСодержимым(СвойстваДокумента, СодержимоеДокумента) Экспорт
	
	СтруктураДокумента = ПодготовитьДанныеДокумента(СодержимоеДокумента);
	СвойстваДокумента.Вставить("Content", СтруктураДокумента.Документ);
	
КонецПроцедуры

#КонецОбласти

#Область Прочее

// Определяет по входящим данным, в каком виде они поступили.
// Будет возращен результат запроса в таким же типом.
//
// Параметры:
//  ДанныеДокумента - ДвоичныеДанные - двоичные данные документа.
//                  - Строка - может быть адресом во временном хранилище или Base64.
//                  - Структура - состоит из двух обязательных полей:
//                  * Ссылка - СправочникСсылка, ДокументСсылка - данные для позиционирования на элементе с данными
//                  * Реквизит - Строка - имя реквизита с типом "ХранилищеЗначения"
//
// Возвращаемое значение:
//  Строка - описание типа документа из фиксированного списка: ДвоичныеДанные, АдресХранилища, Base64, Файл, СсылкаБазы,
//           Неопределено.
//
Функция ПолучитьТипДанныхДокумента(ДанныеДокумента) Экспорт
	
	Результат = "Неопределено";
	
	ЭлементыДанных = ЗначениеВМассиве(ДанныеДокумента);
	ЭлементДанных = ЭлементыДанных[0];
	
	Если ТипЗнч(ЭлементДанных) = Тип("ДвоичныеДанные") Тогда
		Результат = "ДвоичныеДанные";
	ИначеЕсли ТипЗнч(ЭлементДанных) = Тип("Строка") И ЭтоАдресВременногоХранилища(ЭлементДанных) Тогда
		Результат = "АдресХранилища";
	ИначеЕсли ТипЗнч(ЭлементДанных) = Тип("Строка") Тогда
		НашлиСимволы = СтрНайти(ЭлементДанных, ":") > 0 ИЛИ СтрНайти(ЭлементДанных, "\") > 0 ИЛИ СтрНайти(ЭлементДанных, ".") > 0;
		СимволыИдентификатора = СтрЧислоВхождений(ЭлементДанных, "-") = 4 И СтрДлина(ЭлементДанных) = 36;
		Если СимволыИдентификатора Тогда
			Результат = "ИдентификаторХранилища";
		ИначеЕсли НашлиСимволы Тогда
			Результат = "Файл";
		Иначе	
			Результат = "Base64";
		КонецЕсли;	
	ИначеЕсли ТипЗнч(ЭлементДанных) = Тип("Структура") 
		И ЭлементДанных.Свойство("Ссылка") 
		И ЭлементДанных.Свойство("Реквизит") Тогда
		Результат = "СсылкаБазы";
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Служебная функция для подготовки данных документов для передачи на сервере.
// Почти всегда задействован формат в Base64 (кроме случая поточной подписи).
//
// Параметры:
//  ДанныеДокумента 	- ДвоичныеДанные, Строка, Структура - см. ПолучитьТипДанныхДокумента(),
//						если данные переданы как адрес во временном хранилище, результат возвращается в новом адресе временного хранилища.
//						Если данные переданы как ссылка, данные возвращаются как двоичные данные.
//  ДвоичнымиДанными	- Булево - вернуть как двоичные данные
//
// Возвращаемое значение:
//  Структура:
//    * ТипДокумента 	- Строка - определяет в каком формате вернуть результат выполнения операции,
//						определяется на основе входящих данных, варианты: АдресХранилища, Base64, ДвоичныеДанные.
//    * Документ 		- Строка, ДвоичныеДанные - содержимое документа
//
Функция ПодготовитьДанныеДокумента(ДанныеДокумента, ДвоичнымиДанными = Ложь) Экспорт
	
	ТипДокумента = ПолучитьТипДанныхДокумента(ДанныеДокумента);
	
	Результат = Новый Структура;
	Результат.Вставить("ТипДокумента", ТипДокумента);
	Результат.Вставить("Документ", "");
	
	ИсходныйДокумент = "";
	Если ТипДокумента = "ДвоичныеДанные" Тогда
		ИсходныйДокумент = ДанныеДокумента;
	ИначеЕсли ТипДокумента = "АдресХранилища" Тогда 
		ИсходныйДокумент = ПолучитьИзВременногоХранилища(ДанныеДокумента);
	ИначеЕсли ТипДокумента = "Base64" Тогда 
		ИсходныйДокумент = ДанныеДокумента;
	ИначеЕсли ТипДокумента = "СсылкаБазы" Тогда 
		ИсходныйДокумент = СервисКриптографииDSSСлужебныйВызовСервера.ПолучитьДанныеБазыПоСсылке(ДанныеДокумента);
	ИначеЕсли ТипДокумента = "ИдентификаторХранилища" Тогда
		ИсходныйДокумент = ДанныеДокумента;
	КонецЕсли;
	
	Если ТипЗнч(ИсходныйДокумент) = Тип("ДвоичныеДанные") И НЕ ДвоичнымиДанными Тогда
		ИсходныйДокумент = Base64Строка(ИсходныйДокумент);
	ИначеЕсли ТипЗнч(ИсходныйДокумент) = Тип("Строка") И ДвоичнымиДанными Тогда
		ИсходныйДокумент = ПолучитьДвоичныеДанныеИзBase64Строки(ИсходныйДокумент);
	КонецЕсли;
	
	Результат.Вставить("Документ", ИсходныйДокумент);
	
	Если ЗначениеЗаполнено(Результат.Документ) 
		И ДвоичнымиДанными Тогда
		Результат.Вставить("Документ", Результат.Документ);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Возвращает данные сертификата в кодировке DER.
// 
// Параметры:
//   Сертификат			- ДвоичныеДанные - данные сертификата
//   ПроверочныйСимвол	- Строка
// Возвращаемое значение:
//   ДвоичныеДанные - данные сертификата в кодировке DER
// 
Функция СертификатВКодировкеDER(Сертификат, ПроверочныйСимвол = "") Экспорт
	
	Попытка
		СертификатТекст = ПолучитьСтрокуИзДвоичныхДанных(Сертификат);
	Исключение
		СервисКриптографииDSSСлужебныйВызовСервера.ЗаписатьОшибкуВЖурналРегистрации(ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
	КонецПопытки;
		
	Если СтрНайти(СертификатТекст, "-----BEGIN CERTIFICATE-----") > 0 Тогда
		СертификатТекст = СтрЗаменить(СертификатТекст, "-----BEGIN CERTIFICATE-----" + ПроверочныйСимвол, "");
		СертификатТекст = СтрЗаменить(СертификатТекст, ПроверочныйСимвол + "-----END CERTIFICATE-----", "");
		Возврат Base64Значение(СертификатТекст);
	Иначе		
		Возврат Сертификат;
	КонецЕсли;
	
КонецФункции

// Формирует идентификатор версии АПИ сервера.
//
// Параметры:
//  НастройкиПользователя	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//                       	- Строка - содержит версию сервера указанного в "СправочникСсылка.ЭкземплярыСервераDSS".
//	
// Возвращаемое значение:
//  Число
//							
Функция ИдентификаторВерсииСервера(НастройкиПользователя) Экспорт
	
	Если Тип("Строка") = ТипЗнч(НастройкиПользователя) Тогда
		ТекущаяВерсия = НастройкиПользователя;
	Иначе
		ТекущаяВерсия = НастройкиПользователя.ВерсияАПИ;
	КонецЕсли;	
	
	ИДВерсии = 1;
	Если ТекущаяВерсия > "2.0.2882" Тогда
		ИДВерсии = 2;
	КонецЕсли;

	Возврат ИДВерсии;
	
КонецФункции

// Базовая функция для формирования результата выполнения функций и процедур в серверных вызовах.
// Данный формат возврата результата используется в большинстве функций и процедур подсистемы.
// Содержит как обязательные поля, так и дополнительные поля.
// Состав дополнительных полей зависит от состояния операции и вида операции.
// Если "МаркерОбновлен" = Истина, то добавляется поле "НастройкиПользователя".
//
// Параметры: 
//  Выполнено - Булево - устанавливает признак успешности выполнения
//
// Возвращаемое значение:
//  Структура:
//    * Выполнено 		- Булево - признак успешного выполнения вызова.
//						Если Истина, то обычно структура дополняется полем "Результат".
//    * МаркерОбновлен	- Булево - признак, что в процессе работы обновился токен авторизации.
//						Если Истина, структура дополняется полем "НастройкиПользователя".
//    * Ошибка			- Строка - содержит форматированный текст ошибки, если поле Выполнено = Ложь
//    * КодОшибки		- Строка - содержит код ошибки
//    * СтатусОшибки	- см. СервисКриптографииDSSКлиентСервер.СтатусОшибки
//
Функция ОтветСервисаПоУмолчанию(Выполнено = Истина) Экспорт
	
	ОтветМетода 	= Новый Структура;
	ОтветМетода.Вставить("Выполнено", Выполнено);
	ОтветМетода.Вставить("Ошибка", "");
	ОтветМетода.Вставить("КодОшибки", "");
	ОтветМетода.Вставить("МаркерОбновлен", Ложь);
	ОтветМетода.Вставить("СтатусОшибки", СтатусОшибки());
	
	Возврат ОтветМетода;
	
КонецФункции

// Структура для описания статуса ошибки.
//
// Возвращаемое значение:
//  Структура:
//    * Представление	- Строка - содержит форматированный текст ошибки
//    * КодОшибки		- Строка - содержит учетный код ошибки в подсистеме 
//    * ИсходнаяОшибка	- Строка - содержит текст ошибки, сформированный сервером
//    * ИсходныйКод		- Строка - содержит код ошибки, сформированный сервером
//    * ПолныйТекст		- Строка - содержит текст ошибки платформы
//
Функция СтатусОшибки() Экспорт
	
	Результат 	= Новый Структура;
	Результат.Вставить("КодОшибки", "");
	Результат.Вставить("Представление", "");
	Результат.Вставить("ИсходныйТекст", "");
	Результат.Вставить("ИсходныйКод", "");
	Результат.Вставить("ПолныйТекст", "");
	
	Возврат Результат;
	
КонецФункции

// Проверяет значение на массив, создает массив при необходимости и помещает в него переданное значение.
//
// Параметры:
//  Значение 	- Произвольный - любое значение.
//  ЭтоМассив 	- Булево - признак, что переданное значение массив
//
// Возвращаемое значение:
//  Массив
//
Функция ЗначениеВМассиве(Значение, ЭтоМассив = Ложь) Экспорт
	
	Если ТипЗнч(Значение) = Тип("Массив") Тогда
		ЭтоМассив = Истина;
		Результат = Значение;
	Иначе
		ЭтоМассив = Ложь;
		Результат = Новый Массив;
		Результат.Добавить(Значение);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Удаляет значения в структуре с переданными ключами.
//
// Параметры:
//  ТекущаяСтруктура 	- Структура
//  УдалитьСвойства		- Строка - перечисление ключей, разделенные запятыми
//  ОставитьСвойства	- Строка - перечисление ключей, разделенные запятыми, которые нужно оставить
//
Процедура УдалитьСвойство(ТекущаяСтруктура, УдалитьСвойства = "", ОставитьСвойства = "") Экспорт
	
	СписокУдаления = Новый Структура(УдалитьСвойства);
	СписокАктуальных = Новый Структура(ОставитьСвойства);
	МассивКУдалению = Новый Массив;
	
	Если СписокАктуальных.Количество() > 0 Тогда
		Для Каждого СтрокаКлюча Из ТекущаяСтруктура Цикл
			Если НЕ СписокАктуальных.Свойство(СтрокаКлюча.Ключ) Тогда
				МассивКУдалению.Добавить(СтрокаКлюча.Ключ);
			КонецЕсли;
		КонецЦикла;
		
	ИначеЕсли СписокУдаления.Количество() > 0 Тогда
		Для Каждого СтрокаКлюча Из СписокУдаления Цикл
			Если ТекущаяСтруктура.Свойство(СтрокаКлюча.Ключ) Тогда
				МассивКУдалению.Добавить(СтрокаКлюча.Ключ);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	Для Каждого СтрокаМассива Из МассивКУдалению Цикл
		ТекущаяСтруктура.Удалить(СтрокаМассива);
	КонецЦикла;
	
КонецПроцедуры

// Конвертация даты UTC в формате TimeStamp (число) в обычную дату
// 
// Параметры:
//  ЧислоДаты 				- Число
//  ПолучитьМестноеВремя    - Булево
//  Добавка 				- Число - год начала отсчета
// 
// Возвращаемое значение:
//  Дата
//
Функция ДатаUTC(Знач ЧислоДаты, ПолучитьМестноеВремя = Ложь, Добавка = 1970) Экспорт
	
	Результат = Дата(Добавка, 1, 1) + ЧислоДаты;
	
	Если ПолучитьМестноеВремя Тогда
		Результат = МестноеВремя(Результат);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

#КонецОбласти

#Область ОбработкаОшибок

// Формирует параметризированное описание ошибки, по переданном идентификатору ошибки.
// Необходимо отменить, что в модуле формируются ошибки, которые используются на стороне клиента.
// Описание остальных ошибок (исключительно серверных) содержатся в серверном модуле СервисКриптографииDSSСлужебный.ПолучитьОписаниеОшибки.
// 
// Параметры:
//  РезультатОперации 	- Структура, Неопределено - структура со стандартным содержанием ответа сервиса
//  ТипОшибки 			- Строка - ключевое слово возникшей ошибки
//  ТекстОшибки			- Строка - дополнительная информация, включаемая в текст ошибки
//
// Возвращаемое значение:
//  Строка				- описание ошибки в формате "Код ошибки" "Описание ошибки" "Текст ошибки"
//
Функция ПолучитьОписаниеОшибки(РезультатОперации, ТипОшибки, ТекстОшибки = "") Экспорт
	
	Результат = "";
	НашлиОшибку	= Неопределено;
	КодОшибки = "";
	
	Если ЗначениеЗаполнено(ТипОшибки) Тогда
		НашлиОшибку = ДоступныйРеестрОшибок(ТипОшибки);
	КонецЕсли;
	
	Если НашлиОшибку = Неопределено Тогда
		НашлиОшибку = ДоступныйРеестрОшибок("ОшибкаВыполнения");
		Если ЗначениеЗаполнено(ТипОшибки) Тогда
			КодОшибки = НашлиОшибку.КодОшибки;
			НашлиОшибку.КодОшибки = НашлиОшибку.КодОшибки + " (" + ТипОшибки + ")";
		КонецЕсли;
	Иначе
		КодОшибки = НашлиОшибку.КодОшибки;
	КонецЕсли;
	
	Результат = НашлиОшибку.КодОшибки + ": " + НашлиОшибку.Описание;
	Если НЕ ПустаяСтрока(ТекстОшибки) Тогда
		Результат = Результат + Символы.ПС + Символы.ПС 
					+ НСтр("ru = 'Детали ошибки:'") 
					+ Символы.ПС + ТекстОшибки;
	КонецЕсли;	
	
	Если РезультатОперации <> Неопределено Тогда
		РезультатОперации.Вставить("КодОшибки", КодОшибки);
		РезультатОперации.Вставить("Ошибка", Результат);
		РезультатОперации.Вставить("СтатусОшибки", СтатусОшибки());
		РезультатОперации.СтатусОшибки.КодОшибки = КодОшибки;
		РезультатОперации.СтатусОшибки.Представление = Результат;
		РезультатОперации.СтатусОшибки.ИсходныйКод = ТипОшибки;
		РезультатОперации.СтатусОшибки.ИсходныйТекст = ТекстОшибки;
	КонецЕсли;	
	
	Возврат Результат;
	
КонецФункции	

// Проверяет описание ошибки вид ошибок ввода пин-кода
//
// Параметры:
//  ТекстОшибки - Строка - содержание ошибки
//
// Возвращаемое значение:
//  Булево - Истина, если это ошибка при вводе пин-кода сертификата
//
Функция ЭтоОшибкаПинКода(ТекстОшибки) Экспорт
	
	Результат = ПолучитьКодОшибки(ТекстОшибки) = "210009";
	Возврат Результат;
	
КонецФункции

// Проверяет описание ошибки на вид ошибок связанных с аутентификацией
//
// Параметры:
//  ОписаниеОшибки - Строка - содержание ошибки
//
// Возвращаемое значение:
//  Булево - Истина, если это ошибка при аутентификации пользователя
//
Функция ЭтоОшибкаАутентификации(ОписаниеОшибки) Экспорт
	
	Результат = Ложь;
	
	Если Сред(ОписаниеОшибки, 1, 2) = "20"
		ИЛИ Сред(ОписаниеОшибки, 1, 6) = "000003" Тогда
		Результат = Истина;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Проверяет описание ошибки на вид ошибок отказа пользователя от продолжения операции
//
// Параметры:
//  ТекстОшибки - Строка - содержание ошибки
//
// Возвращаемое значение:
//   Булево - Истина, если это ошибка при отказе пользователя
//
Функция ЭтоОшибкаОтказа(ТекстОшибки) Экспорт
	
	Результат = ПолучитьКодОшибки(ТекстОшибки) = "210000"
				ИЛИ ПолучитьКодОшибки(ТекстОшибки) = "210001"
				ИЛИ ПолучитьКодОшибки(ТекстОшибки) = "300045";
	Возврат Результат;
	
КонецФункции

// Проверяет описание ошибки на вид ошибок наличие необработанного запроса на сертификат
//
// Параметры:
//  ТекстОшибки - Строка - содержание ошибки
//
// Возвращаемое значение:
//  Булево - Истина, если это ошибка этого вида
//
Функция ЭтоОшибкаНеобработанныеЗапросы(ТекстОшибки) Экспорт
	
	Результат = ПолучитьКодОшибки(ТекстОшибки) = "300011";
	Возврат Результат;
	
КонецФункции

// Возвращает код ошибки из содержание ошибки
//
// Параметры:
//  ТекстОшибки - Строка - содержание ошибки
//
// Возвращаемое значение:
//  Строка - строка из 6 символов обозначающая код ошибки
//
Функция ПолучитьКодОшибки(ТекстОшибки) Экспорт
	
	Результат = "";
	Позиция = СтрНайти(ТекстОшибки, ":");
	Если Позиция = 7 Тогда
		Результат = Сред(ТекстОшибки, 1, 6);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Формирует представление структуры запроса, необходимая для записи в журнал регистрации.
//
// Параметры:
//  ВходящийКонтекст - Структура, Произвольный - содержание данных
//
// Возвращаемое значение:
//  Строка - представление структуры
//
Функция ФильтроватьПараметрыВызова(ВходящийКонтекст) Экспорт
	
	Результат = "";
	
	КлючевыеПоля = Новый Соответствие;
	КлючевыеПоля.Вставить("password", "");
	КлючевыеПоля.Вставить("client_id", "");
	КлючевыеПоля.Вставить("oldpin", "");
	КлючевыеПоля.Вставить("newpin", "");
	КлючевыеПоля.Вставить("pin", "");
	КлючевыеПоля.Вставить(НРег("НастройкиПользователя"), "");
	КлючевыеПоля.Вставить("пароль", "");
	КлючевыеПоля.Вставить(НРег("пинкод"), "");
	КлючевыеПоля.Вставить(НРег("ПарольПользователя"), "");
	
	ФильтроватьПараметрыВызоваРекурсивно(Результат, ВходящийКонтекст, КлючевыеПоля);
	
	Возврат Результат;
	
КонецФункции

// Возвращает имя события для журнала регистрации, которое используется для записи ошибок в подсистеме облачной подписи.
//
// Возвращаемое значение:
//  Строка - имя события.
//
Функция ИмяСобытияЖурналаРегистрации() Экспорт
	
	Возврат НСтр("ru = 'Сервис криптографии DSS'");
	
КонецФункции

// Формирует результат выполнения операции, по факту проверки поддерживаемой версии АПИ
//
// Параметры:
//  НастройкиПользователя 	- Структура 
//                        	- Строка
//  РеестрИдВерсий			- Строка - перечисление идентификаторов версий, через запятую
//
// Возвращаемое значение:
//   см. СервисКриптографииDSSКлиентСервер.ОтветСервисаПоУмолчанию
//	
Функция ПроверитьВерсиюСервера(НастройкиПользователя, Знач РеестрИдВерсий) Экспорт
	
	Результат 	= Новый Структура;
	Результат.Вставить("Выполнено", Истина);
	Результат.Вставить("Ошибка", "");
	Результат.Вставить("КодОшибки", "");
	Результат.Вставить("МаркерОбновлен", Ложь);
	
	РеестрИдВерсий 		= СтрЗаменить(РеестрИдВерсий, " ", "");
	РазрешенныеВерсии 	= СтрРазделить(РеестрИдВерсий, ",", Ложь);
	ИдВерсии 			= Формат(ИдентификаторВерсииСервера(НастройкиПользователя), "ЧГ=0");
	
	Если РазрешенныеВерсии.Найти(ИдВерсии) = Неопределено Тогда
		Результат.Выполнено = Ложь;
		СервисКриптографииDSSСлужебныйВызовСервера.ПолучитьОписаниеОшибки(Результат, "НеПоддерживаемаяВерсия");
	КонецЕсли;
	
	Возврат Результат;

КонецФункции

#КонецОбласти

#Область ИсточникХраненияНастроекПользователя

// Формирует идентификатор способа хранения сессионных настроек пользователя,  использующие регистр сведений "БезопасноеХранилищеДанных".
//
// Возвращаемое значение:
//  Строка
//
Функция ИсточникНастроекХранилище() Экспорт
	
	Возврат "Хранилище";
	
КонецФункции

// Формирует идентификатор способа хранения сессионных настроек пользователя, использующие параметры сеанса.
//
// Возвращаемое значение:
//  Строка
//
Функция ИсточникНастроекПараметрыСеанса() Экспорт
	
	Возврат "ПараметрыСеанса";
	
КонецФункции

#КонецОбласти

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

#Область ПодтверждениеОпераций

// Процедура для анализа ответа сервиса на аутентификационное испытание в процессе подтверждения операций
// По результатам анализа заполняются данные цикла подтверждения.
//
// Параметры:
//  РезультатЗапроса 		- Структура - ответ сервиса облачной подписи
//  НастройкиПользователя 	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//  ДанныеПодтверждения 	- см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//  ДатаСеанса 				- Дата - используется для вычисления времени даты и времени действия созданной транзакции
//  ПараметрыОперации	 	- Структура, ФиксированнаяСтруктура - позволяет указать дополнительные параметры операции.
// 
Процедура РазобратьРезультатЗапроса(РезультатЗапроса, 
									НастройкиПользователя, 
									ДанныеПодтверждения, 
									ДатаСеанса, 
									ПараметрыОперации = Неопределено) Экспорт
	
	НовыйЭтап = ДанныеПодтверждения.ЭтапЦикла;
	ВторичнаяАвторизация = ДанныеПодтверждения.ВторичнаяАвторизация;
	ТекстОшибки = "";
	КодОшибки = "";
	
	Если РезультатЗапроса.Выполнено Тогда
		АнализОтвета = РезультатЗапроса.Результат;
		Если РезультатЗапроса.МаркерОбновлен Тогда
			СервисКриптографииDSSСлужебныйВызовСервера.ОбновитьНастройкиПользователя(НастройкиПользователя, РезультатЗапроса.НастройкиПользователя, ПараметрыОперации);
		КонецЕсли;
		
		Если ПолучитьПолеСтруктуры(АнализОтвета, "IsError", Истина) Тогда
			ТипОшибки = ПолучитьПолеСтруктуры(АнализОтвета, "Error", "");
			Если ТипОшибки = "authentication_declined" Тогда
				НовыйЭтап = "Отказ";	
			Иначе	
				НовыйЭтап = "Ошибка";	
			КонецЕсли;
			СервисКриптографииDSSСлужебныйВызовСервера.ПолучитьОписаниеОшибки(РезультатЗапроса, ТипОшибки);
			КодОшибки = РезультатЗапроса.КодОшибки;
			ТекстОшибки = ПолучитьПолеСтруктуры(АнализОтвета, "ErrorDescription", "");	
			
		ИначеЕсли ПолучитьПолеСтруктуры(АнализОтвета, "IsFinal", Истина) Тогда
			РезультатВыполнения = СервисКриптографииDSSСлужебныйВызовСервера.ПроверитьМаркерДоступа(НастройкиПользователя, РезультатЗапроса, ПараметрыОперации);
			
			НовыйЭтап = "Окончание";
			Если РезультатВыполнения.Выполнено Тогда
				НовыйЭтап = "Окончание";
			Иначе
				НовыйЭтап = "Ошибка";
				КодОшибки = РезультатВыполнения.КодОшибки;
				ТекстОшибки = РезультатВыполнения.Ошибка;
				РезультатЗапроса = РезультатВыполнения;
			КонецЕсли;	
			
		ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "ВводКода" Тогда
			ИщемОшибку = ПолучитьПолеСтруктуры(АнализОтвета, "Challenge.Title.Value", "");
			Если ЗначениеЗаполнено(ИщемОшибку) Тогда
				ДанныеПодтверждения.ОписаниеПодтверждения = ИщемОшибку;
				НовыйЭтап = "Предупреждение";	
			КонецЕсли;	
			
		ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Выбор" Тогда
			ПолучитьДанныеВторичнойАвторизации(АнализОтвета, ДанныеПодтверждения, ДатаСеанса);
			Если ЭтоМобильноеПриложениеДляПодтверждения(ДанныеПодтверждения.ВторичнаяАвторизация) Тогда
				НовыйЭтап	= "Ожидание";
			Иначе	
				НовыйЭтап	= "ВводКода";
			КонецЕсли;
			
		ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Начало" Тогда
			ВсегоМетодов = ПолучитьМетодыВторичнойАвторизации(АнализОтвета, ДанныеПодтверждения, ВторичнаяАвторизация);
			Если ДанныеПодтверждения.СписокМетодов.Количество() = 0 Тогда
				НовыйЭтап 	= "Ошибка";	
				ТекстОшибки = СервисКриптографииDSSСлужебныйВызовСервера.ПолучитьОписаниеОшибки(Неопределено, "МетодАвторизации");
			ИначеЕсли ВсегоМетодов = 1 Тогда
				ПолучитьДанныеВторичнойАвторизации(АнализОтвета, ДанныеПодтверждения, ДатаСеанса);
				Если ЭтоМобильноеПриложениеДляПодтверждения(ДанныеПодтверждения.ВторичнаяАвторизация) Тогда
					НовыйЭтап	= "Ожидание";
				Иначе	
					НовыйЭтап	= "ВводКода";
				КонецЕсли;
			Иначе	
				НовыйЭтап	= "Выбор";
			КонецЕсли;	
		КонецЕсли;
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Предупреждение" Тогда
		НовыйЭтап	= "ВводКода";
		
	Иначе
		НовыйЭтап 	= "Ошибка";	
		ТекстОшибки = РезультатЗапроса.Ошибка;	
		
	КонецЕсли;	
	
	Если НовыйЭтап = "Ошибка" Тогда
		ДанныеПодтверждения.Ошибка = ТекстОшибки;
		ДанныеПодтверждения.КодОшибки = КодОшибки;
	КонецЕсли;
	
	Если ДанныеПодтверждения.ЭтапЦикла <> НовыйЭтап Тогда
		ДанныеПодтверждения.ЭтапЦикла = НовыйЭтап;
	КонецЕсли;	
	
КонецПроцедуры

// Функция для формирования параметров запроса к сервису облачной подписи в зависимости от состояния
// данных цикла подтверждения.
//
// Параметры:
//  НастройкиПользователя 	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//  ДанныеПодтверждения 	- см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//	
// Возвращаемое значение:
//  Структура - сформированные параметры для запроса к сервису. Содержит различные необязательные поля:
//    * ClientId					- Строка
//    * Resource					- Строка
//    * TransactionTokenId			- Строка
//    * ConfirmationScope			- Строка
//    * ConfirmationParams			- Структура:
//      ** Templte					- Строка
//    * Resource					- Строка
//    * ChallengeResponse			- Структура:
//      ** ChoiceChallengeResponse	- Массив из Структура:
//        *** RefId					- Строка
//        *** ChoiceSelected		- Массив из Структура:
//          **** RefID				- Строка
//      ** TextChallengeResponse	- Массив из Структура:
//        *** RefId					- Строка
//        *** ChoiceSelected		- Массив из Структура:
//          **** RefID				- Строка
//          **** Value				- Строка
//
Функция ПодготовитьПараметрыОтправкиЗапроса(НастройкиПользователя, ДанныеПодтверждения) Экспорт
	
	ПараметрыЗапроса = Новый Структура;
	
	Если ДанныеПодтверждения.ЭтапЦикла = "Начало" Тогда
		ПараметрыЗапроса.Вставить("Resource", НРег(НастройкиПользователя.Подключение.ИдентификаторПодписи));
		НуженИдентификатор = Ложь;
		Если ДанныеПодтверждения.ТипПодтверждения = "Транзакция" Тогда
			НуженИдентификатор = Истина;
		ИначеЕсли ДанныеПодтверждения.ТипПодтверждения = "ПроизвольнаяОперация" Тогда
			Если ЗначениеЗаполнено(ДанныеПодтверждения.ИдентификаторТранзакции) ИЛИ ЗначениеЗаполнено(ДанныеПодтверждения.ИдентификаторОперации) Тогда
				НуженИдентификатор = Истина;
			Иначе	
				ПараметрыЗапроса.Вставить("ConfirmationScope", ДанныеПодтверждения.ШаблонПодтверждения);
				ПараметрыЗапроса.Вставить("ConfirmationParams", Новый Структура("Templte", ДанныеПодтверждения.Заголовок));
			КонецЕсли;	
		КонецЕсли;
		
		Если НуженИдентификатор Тогда
			Если ЗначениеЗаполнено(ДанныеПодтверждения.ИдентификаторОперации) И ДанныеПодтверждения.ВерсияПодтверждения = 2 Тогда
				ПараметрыЗапроса.Вставить("OperationId", ДанныеПодтверждения.ИдентификаторОперации);
			Иначе
				ПараметрыЗапроса.Вставить("TransactionTokenId", ДанныеПодтверждения.ИдентификаторТранзакции);
			КонецЕсли;
		КонецЕсли;
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Выбор" Тогда
		ВсеТипыПодтверждений = ТипыВторичнойАвторизации();
		Если ДанныеПодтверждения.ВторичнаяАвторизация = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_DSSSDK") Тогда
			ПервыйЭлемент = Неопределено;
			ВсегоЭлементов = 0;
			Для Каждого СтрокаМассива Из ДанныеПодтверждения.СписокМетодов Цикл
				Если СтрокаМассива.Тип = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_DSSSDK") Тогда
					ВсегоЭлементов = ВсегоЭлементов + 1;
					ПервыйЭлемент = СтрокаМассива;
				КонецЕсли;
			КонецЦикла;
			Если ВсегоЭлементов = 1 Тогда
				ДанныеПодтверждения.ВторичнаяАвторизация = ПервыйЭлемент.Идентификатор;
			КонецЕсли;
		КонецЕсли;
		
		ОписаниеПодтверждения = НайтиОписаниеВторичнойАвторизации(ДанныеПодтверждения.СписокМетодов, ДанныеПодтверждения.ВторичнаяАвторизация);
		Если ОписаниеПодтверждения.Адрес Тогда
			ИдентификаторПодтверждения = ОписаниеПодтверждения.Идентификатор;
		Иначе
			ИдентификаторПодтверждения = ВсеТипыПодтверждений[ДанныеПодтверждения.ВторичнаяАвторизация];
		КонецЕсли;
		
		НовыйЭлемент = Новый Структура;
		НовыйЭлемент.Вставить("RefId", ДанныеПодтверждения.Идентификатор);
		НовыйЭлемент.Вставить("ChoiceSelected", Новый Массив);
		ОписаниеВыбора = Новый Структура;
		ОписаниеВыбора.Вставить("RefID", ИдентификаторПодтверждения);
		НовыйЭлемент.ChoiceSelected.Добавить(ОписаниеВыбора);
		
		МассивВыбора = Новый Массив;
		МассивВыбора.Добавить(НовыйЭлемент);
		
		ПараметрыЗапроса.Вставить("Resource", НастройкиПользователя.Подключение.ИдентификаторПодписи);
		ПараметрыЗапроса.Вставить("ChallengeResponse", Новый Структура);
		ПараметрыЗапроса.ChallengeResponse.Вставить("ChoiceChallengeResponse", МассивВыбора);
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "ВводКода" Тогда
		НовыйЭлемент		= Новый Структура;
		НовыйЭлемент.Вставить("RefId", ДанныеПодтверждения.Идентификатор);
		НовыйЭлемент.Вставить("Value", ДанныеПодтверждения.КодПользователя);
		
		МассивВыбора = Новый Массив;
		МассивВыбора.Добавить(НовыйЭлемент);
		
		ПараметрыЗапроса.Вставить("Resource", НастройкиПользователя.Подключение.ИдентификаторПодписи);
		ПараметрыЗапроса.Вставить("ChallengeResponse", Новый Структура);
		ПараметрыЗапроса.ChallengeResponse.Вставить("TextChallengeResponse", МассивВыбора);
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Ожидание" Тогда
		НовыйЭлемент		= Новый Структура;
		НовыйЭлемент.Вставить("RefId", ДанныеПодтверждения.Идентификатор);
		
		МассивВыбора = Новый Массив;
		МассивВыбора.Добавить(НовыйЭлемент);
		
		ПараметрыЗапроса.Вставить("Resource", НастройкиПользователя.Подключение.ИдентификаторПодписи);
		ПараметрыЗапроса.Вставить("ChallengeResponse", Новый Структура);
		ПараметрыЗапроса.ChallengeResponse.Вставить("TextChallengeResponse", МассивВыбора);
		
	КонецЕсли;
	
	Если ПараметрыЗапроса.Количество() > 0 Тогда
		ПараметрыЗапроса.Вставить("ClientId", НастройкиПользователя.Подключение.ИдентификаторКлиента);
	КонецЕсли;
	
	Возврат ПараметрыЗапроса;
	
КонецФункции

#КонецОбласти

#Область ФормированиеОписаниеОшибок

Функция ДоступныйРеестрОшибок(Знач ИдентификаторОшибки)
	
	Результат = Неопределено;
	ИдентификаторОшибки = НРег(ИдентификаторОшибки);
	
	Если ИдентификаторОшибки = НРег("СертификатыНеОбнаружены") Тогда
		Результат = ОписаниеОшибки_СертификатыНеОбнаружены();
	ИначеЕсли ИдентификаторОшибки = НРег("ОшибкаВыполнения") Тогда
		Результат = ОписаниеОшибки_ОшибкаВыполнения();
	ИначеЕсли ИдентификаторОшибки = НРег("РасшифровкаВЦикле") Тогда
		Результат = ОписаниеОшибки_РасшифровкаВЦикле();
	ИначеЕсли ИдентификаторОшибки = НРег("Отказ") Тогда
		Результат = ОписаниеОшибки_Отказ();
	ИначеЕсли ИдентификаторОшибки = "authentication_declined" Тогда
		Результат = ОписаниеОшибки_authentication_declined();
	ИначеЕсли ИдентификаторОшибки = "certificate_not_found" Тогда
		Результат = ОписаниеОшибки_certificate_not_found();
	ИначеЕсли ИдентификаторОшибки = НРег("ТипПодписи") Тогда
		Результат = ОписаниеОшибки_ТипПодписи();
	ИначеЕсли ИдентификаторОшибки = НРег("ОтказПользователя") Тогда
		Результат = ОписаниеОшибки_ОтказПользователя();
	ИначеЕсли ИдентификаторОшибки = НРег("УстановкаРасширенияСФайлами") Тогда
		Результат = ОписаниеОшибки_УстановкаРасширенияСФайлами();
	ИначеЕсли ИдентификаторОшибки = НРег("ПолучениеФайла") Тогда
		Результат = ОписаниеОшибки_ПолучениеФайла();
	ИначеЕсли ИдентификаторОшибки = НРег("НеподдерживаемаяВерсия") Тогда
		Результат = ОписаниеОшибки_НеПоддерживаемаяВерсия();
	ИначеЕсли ИдентификаторОшибки = НРег("МетодАвторизации") Тогда
		Результат = ОписаниеОшибки_МетодАвторизации();
	ИначеЕсли ИдентификаторОшибки = НРег("ПоляВыбранногоЗапросаНаСертификат") Тогда
		Результат = ОписаниеОшибки_ПоляВыбранногоЗапросаНаСертификат();
	ИначеЕсли ИдентификаторОшибки = НРег("ЗавершениеРаботы") Тогда
		Результат = ОписаниеОшибки_ЗавершениеРаботы();
	ИначеЕсли ИдентификаторОшибки = НРег("ОбработкаНастроекЗаявления") Тогда
		Результат = ОписаниеОшибки_ОбработкаНастроекЗаявления();
	ИначеЕсли ИдентификаторОшибки = НРег("ОтсутствиеНастроек") Тогда
		Результат = ОписаниеОшибки_ОбработкаОтсутствиеНастроек();
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Формирует структуру для хранения описания ошибки.
// 
// Параметры:
//  КодОшибки 	- Строка
//  ТекстОшибки - Строка - текст описания ошибки
//
// Возвращаемое значение:
//  Структура:
//    * КодОшибки - Строка
//    * Описание 	- Строка - текст описания ошибки
//
Функция ОбщееОписаниеОшибки(КодОшибки, ТекстОшибки)
	
	Результат = Новый Структура();
	Результат.Вставить("КодОшибки", КодОшибки);
	Результат.Вставить("Описание", ТекстОшибки);
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_СертификатыНеОбнаружены()
	
	Результат = ОбщееОписаниеОшибки("100002", 
			НСтр("ru = 'Сообщение зашифровано неизвестными сертификатами.'"));
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_ОшибкаВыполнения()
	
	Результат = ОбщееОписаниеОшибки("100003", 
			НСтр("ru = 'Ошибка сервиса.
			|1. Возможно сервер сейчас не доступен, проверьте настройки сети и работоспособность сервера.
			|2. Неправильные параметры запроса.
			|3. Проверьте настройки и права сервера 1С на подключение к сервису DSS.
			|4. Проверьте настройки для TLS подключения (сертификаты сервера).'"));	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_РасшифровкаВЦикле()
	
	Результат = ОбщееОписаниеОшибки("100004", 
			НСтр("ru = 'Не удалось расшифровать документ по данным всех учетных записей'"));
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_Отказ()
	
	Результат = ОбщееОписаниеОшибки("210000", 
			НСтр("ru = 'Пользователь отказался от аутентификации.'"));
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_authentication_declined()
	
	Результат = ОбщееОписаниеОшибки("210001", 
			НСтр("ru = 'Пользователь отказался от подтверждения операции.'"));
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_МетодАвторизации()
	
	Результат = ОбщееОписаниеОшибки("200003", 
			НСтр("ru = 'Не обнаружены доступные способы подтверждения в настройках сервиса.'"));
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_certificate_not_found()
	
	Результат = ОбщееОписаниеОшибки("300006", 
			НСтр("ru = 'Сертификат не обнаружен.'"));
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_ТипПодписи()
	
	Результат = ОбщееОписаниеОшибки("300044", 
			НСтр("ru = 'Данный тип подписи не поддерживается сервером DSS.'"));
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_ОтказПользователя()
	
	Результат = ОбщееОписаниеОшибки("300045", 
			НСтр("ru = 'Пользователь отказался от выбранного действия.'"));
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_УстановкаРасширенияСФайлами()
	
	Результат = ОбщееОписаниеОшибки("300046", 
			НСтр("ru = 'Не удалось установить расширение работы с файлами в веб-клиенте.'"));
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_ПолучениеФайла()
	
	Результат = ОбщееОписаниеОшибки("300047", 
			НСтр("ru = 'Не удалось получить данные файла.'"));
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_НеПоддерживаемаяВерсия()
	
	Результат = ОбщееОписаниеОшибки("300052", 
			НСтр("ru = 'Запрос требуемого ресурса не поддерживается текущий версией сервера DSS.'"));
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_ПоляВыбранногоЗапросаНаСертификат()
	
	Результат = ОбщееОписаниеОшибки("300068", 
			НСтр("ru = 'В выбранном запросе на сертификат атрибуты отличаются от указанных пользователем.'"));
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_ЗавершениеРаботы()
	
	Результат = ОбщееОписаниеОшибки("300070", 
			НСтр("ru = 'Завершение работы системы.'"));
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_ОбработкаНастроекЗаявления()
	
	Результат = ОбщееОписаниеОшибки("300072", 
			НСтр("ru = 'Ошибка при обработке настроек заявления.'"));
	
	Возврат Результат;
	
КонецФункции

// Формирует описание ошибки
// 
// Возвращаемое значение:
//   см. ОбщееОписаниеОшибки
//
Функция ОписаниеОшибки_ОбработкаОтсутствиеНастроек()
	
	Результат = ОбщееОписаниеОшибки("300073", 
			НСтр("ru = 'Для операций проверки подписи или сертификата не найдены настройки подключения.'"));
	
	Возврат Результат;
	
КонецФункции

#КонецОбласти

#Область ВспомогательныеПроцедурыИФункции

// Служебная функция для получения реестра типов вторичной авторизации типа для аутентификационного испытания
// варианты методов.
// 	otpviasms (SMS),
//	mobile (myDSS),
// 	airkey (AirKeyDSS),
// 	oath,
// 	simauth,
// 	otpviaemail (почта),
// 	mtmo.
//
// Параметры:
//  Перечисление - см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//
// Возвращаемое значение:
//   Соответствие из КлючИЗначение:
//    * Ключ - ПеречислениеСсылка.СпособыАвторизацииDSS
//    * Значение - Строка - представление метода
//
Функция ТипыВторичнойАвторизации()
	
	Префикс				= "http://dss.cryptopro.ru/identity/authenticationmethod/";
	
	Результат 			= Новый Соответствие;
	Результат.Вставить(ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_МобильноеПриложение"), Префикс + "mobile");
	Результат.Вставить(Префикс + "mobile", ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_МобильноеПриложение"));
	
	Результат.Вставить(ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_СМС"), Префикс + "otpviasms");
	Результат.Вставить(Префикс + "otpviasms", ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_СМС"));
	
	Результат.Вставить(ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_ЭлектроннаяПочта"), Префикс + "otpviaemail");
	Результат.Вставить(Префикс + "otpviaemail", ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_ЭлектроннаяПочта"));
	
	Результат.Вставить(ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_AirKeyLite"), Префикс + "airkey");
	Результат.Вставить(Префикс + "airkey", ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_AirKeyLite"));
	
	Результат.Вставить(ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_DSSSDK"), Префикс + "mydss");
	Результат.Вставить(Префикс + "mydss", ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_DSSSDK"));
	
	Возврат Результат;
	
КонецФункции

// Служебная процедура для разбора аутентификационного испытания в процессе процедуры подтверждения
// и заполнения данных цикла подтверждения.
//
// Параметры:
//  ДанныеОтвета 		- Структура - значение аутентификационного испытания
//  ДанныеПодтверждения - см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//
Процедура ПолучитьДанныеВторичнойАвторизации(ДанныеОтвета, ДанныеПодтверждения, ДатаСеанса)
	
	ВторичныйМетод = ОписаниеВторичнойАвторизации(ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.TextChallenge[0].AuthnMethod", ""));
	
	ДанныеПодтверждения.Идентификатор = ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.TextChallenge[0].RefID", "");
	ДанныеПодтверждения.ОписаниеПодтверждения = ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.TextChallenge[0].Label", "");
	ДанныеПодтверждения.ГрафическийКод = Неопределено;
	
	Если ВторичныйМетод.Тип <> ОписаниеВторичнойАвторизации(ДанныеПодтверждения.ВторичнаяАвторизация).Тип Тогда
		ДанныеПодтверждения.ВторичнаяАвторизация = ВторичныйМетод.Идентификатор;
	КонецЕсли;
	
	ДанныеГрафическогоКода			= ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.TextChallenge[0].Image");
	СрокДействия					= ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.TextChallenge[0].ExpiresIn", 0);
	ВремяСоздания					= ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.TextChallenge[0].CreatedAt", 0);
	
	Если ЗначениеЗаполнено(ДанныеГрафическогоКода) Тогда
		ДанныеПодтверждения.ГрафическийКод = ПолучитьДвоичныеДанныеИзBase64Строки(ДанныеГрафическогоКода.Value);
	КонецЕсли;
	
	Если ДанныеПодтверждения.ДоступныеМетоды.Найти(ДанныеПодтверждения.ВторичнаяАвторизация) = Неопределено Тогда
		ДанныеПодтверждения.ЭтапЦикла = "Ошибка";	
		ДанныеПодтверждения.Ошибка 	= СервисКриптографииDSSСлужебныйВызовСервера.ПолучитьОписаниеОшибки(Неопределено, "МетодАвторизации");
	КонецЕсли;	
	
	Если СрокДействия > 0 И ВремяСоздания Тогда
		ДанныеПодтверждения.СрокДействия = ДатаUTC(ВремяСоздания, Истина) + СрокДействия;
	ИначеЕсли СрокДействия > 0 Тогда
		ДанныеПодтверждения.СрокДействия = ДатаСеанса + СрокДействия;
	Иначе
		ДанныеПодтверждения.СрокДействия = Неопределено;
	КонецЕсли;
	
КонецПроцедуры	

// Служебная процедура для разбора первого этапа аутентификационного испытания - выбор способа подтверждения
// и заполнения данных цикла подтверждения.
//
// Параметры:
//  ДанныеОтвета - Структура - значение аутентификационного испытания
//  ДанныеПодтверждения - см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//  ВторичнаяАвторизация - ПеречислениеСсылка.СпособыАвторизацииDSS
//
Функция ПолучитьМетодыВторичнойАвторизации(ДанныеОтвета, ДанныеПодтверждения, ВторичнаяАвторизация)
	
	Результат = 0;
	
	ДанныеПодтверждения.СписокМетодов.Очистить();
	
	НесколькоМетодов = ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.ChoiceChallenge");
	Если НесколькоМетодов <> Неопределено Тогда
		НесколькоМетодов = ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.ChoiceChallenge[0].Choice");
		Результат = НесколькоМетодов.Количество();
		Для каждого СтрокаМассива Из НесколькоМетодов Цикл
			ДополнитьСписокТиповАвторизации(ДанныеПодтверждения, ПолучитьПолеСтруктуры(СтрокаМассива, "RefID", ""), ПолучитьПолеСтруктуры(СтрокаМассива, "Label"));
		КонецЦикла;
		ДанныеПодтверждения.ОписаниеПодтверждения = ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.Title.Value", "");
		ДанныеПодтверждения.Идентификатор = ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.ContextData.RefID", "");
		
	Иначе
		Результат = 1;
		ДополнитьСписокТиповАвторизации(ДанныеПодтверждения, ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.TextChallenge[0].AuthnMethod", ""));
		ДанныеПодтверждения.ОписаниеПодтверждения = ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.TextChallenge[0].Label", "");
		ДанныеПодтверждения.Идентификатор = ПолучитьПолеСтруктуры(ДанныеОтвета, "Challenge.TextChallenge[0].RefID", "");
		
	КонецЕсли;
	
	Если НЕ ЗначениеЗаполнено(НайтиОписаниеВторичнойАвторизации(ДанныеПодтверждения.СписокМетодов, ВторичнаяАвторизация)) Тогда
		ВторичнаяАвторизация = Неопределено;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Служебная процедура участвуют в рекурсивном формировании представления структуры.
// При этом исключается содержание объемных и конфиденциальных блоков данных.
//
// Параметры:
//  НовыйОбъект 		- Произвольный
//  ВходящийКонтекст 	- Структура
//  КлючевыеПоля 		- Структура - исключаемые поля
//
Процедура ФильтроватьПараметрыВызоваРекурсивно(НовыйОбъект, ВходящийКонтекст, КлючевыеПоля)
	
	ТипКонтекста = ТипЗнч(ВходящийКонтекст);
	
	Если Тип("Строка") = ТипКонтекста Тогда // ограничим длину и проверим на пароль
		Представление = Лев(ВходящийКонтекст, 50);
		Позиция = СтрНайти(НРег(Представление), "password");
		Если Позиция > 0 Тогда
			Представление = Сред(Представление, 1, Позиция - 1);
		КонецЕсли;
		НовыйОбъект = НовыйОбъект + Представление;
		
	ИначеЕсли Тип("ДвоичныеДанные") = ТипКонтекста Тогда
		НовыйОбъект = НовыйОбъект + "<<ДвоичныеДанные>>";
		
	ИначеЕсли Тип("Массив") = ТипКонтекста 
		ИЛИ Тип("ФиксированныйМассив") = ТипКонтекста Тогда
		НовыйОбъект = НовыйОбъект + "[";
		Для каждого СтрокаМассива Из ВходящийКонтекст Цикл
			ФильтроватьПараметрыВызоваРекурсивно(НовыйОбъект, СтрокаМассива, КлючевыеПоля);
			НовыйОбъект = НовыйОбъект + "," + Символы.ПС;
		КонецЦикла;	
		НовыйОбъект = НовыйОбъект + "]";
		
	ИначеЕсли Тип("Структура") = ТипКонтекста 
		ИЛИ Тип("ФиксированнаяСтруктура") = ТипКонтекста 
		ИЛИ Тип("Соответствие") = ТипКонтекста 
		ИЛИ Тип("ФиксированноеСоответствие") = ТипКонтекста Тогда
		
		НовыйОбъект = НовыйОбъект + "{";
		Для каждого СтрокаКлюча Из ВходящийКонтекст Цикл
			КлючСтроки = НРег(СокрЛП(СтрокаКлюча.Ключ));
			ЗначениеСтроки = СтрокаКлюча.Значение;
			
			НовыйОбъект = НовыйОбъект + КлючСтроки + "=";
			Если КлючевыеПоля[КлючСтроки] <> Неопределено Тогда
				ЗначениеСтроки = "******";
			КонецЕсли;
			
			ФильтроватьПараметрыВызоваРекурсивно(НовыйОбъект, ЗначениеСтроки, КлючевыеПоля);
			НовыйОбъект = НовыйОбъект + "," + Символы.ПС;
		КонецЦикла;	
		НовыйОбъект = НовыйОбъект + "}";
		
	ИначеЕсли Тип("Число") = ТипКонтекста Тогда
		НовыйОбъект = НовыйОбъект + Формат(ВходящийКонтекст, "ЧН=; ЧГ=");
		
	Иначе
		НовыйОбъект = НовыйОбъект + СокрЛП(ВходящийКонтекст);
		
	КонецЕсли;	
	
КонецПроцедуры	

// Служебная функция, проверяет строковое значение, что оно целое число
//
// Параметры:
//  ПроверяемоеЗначение - Строка
//
// Возвращаемое значение:
//  Булево
//
Функция ЭтоЦелоеЧисло(Знач ПроверяемоеЗначение) 
	
	Если ПроверяемоеЗначение = "0" Тогда
		Возврат Истина;
	КонецЕсли;
	
	ОписаниеЧисла = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(10, 0, ДопустимыйЗнак.Неотрицательный));
	
	Возврат ОписаниеЧисла.ПривестиЗначение(ПроверяемоеЗначение) <> 0;
	
КонецФункции

// Служебная функция, проверяет имя поля на соответствие имени переменной
//
// Параметры:
//  ПроверяемоеЗначение - Строка
//
// Возвращаемое значение:
//  Булево
//
Функция ЭтоИмяПеременной(Знач ПроверяемоеЗначение)
	
	Результат   = ЗначениеЗаполнено(ПроверяемоеЗначение);
	ВсеБуквы 	= "_QWERTYUIOPASDFGHJKLZXCVBNM" + "ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ";
	ВсеЦифры 	= "01234566789";
	ПроверяемоеЗначение = ВРег(ПроверяемоеЗначение);
	
	Если СтрНайти(ВсеБуквы, Лев(ПроверяемоеЗначение, 1)) = 0 Тогда
		Результат = Ложь;
	Иначе
		ВсеБуквы = ВсеБуквы + ВсеЦифры;
		Для Счетчик = 1 По СтрДлина(ПроверяемоеЗначение) Цикл
			Если СтрНайти(ВсеБуквы, Сред(ПроверяемоеЗначение, Счетчик, 1)) = 0 Тогда
				Результат = Ложь;
				Прервать;
			КонецЕсли;	
		КонецЦикла;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Служебная, определяет ключ для сохранения и получения настроек из параметра сеанса
//
// Параметры:
//  НастройкиПользователя 	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//
// Возвращаемое значение:
//  - Строка
//  - СправочникСсылка.УчетныеЗаписиDSS
//
Функция КлючНастроекПользователя(НастройкиПользователя) Экспорт
	
	Если НастройкиПользователя.ДанныеБД Тогда
		Результат = НастройкиПользователя.Ссылка;
	Иначе
		Результат = НастройкиПользователя.Логин + НастройкиПользователя.Подключение.Сервер;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Запутывает содержание пароля введенного пользователем, прежде чем он будет передан на сервер.
//
// Параметры:
//  ВведенныйСекрет 			- Строка
//  АвторизованныйПользователь	- СправочникСсылка.Пользователи - ссылка на текущего пользователя
//  ПризнакКонфиденциальности 	- Число - применяемый алгоритм
//
// Возвращаемое значение:
//  Строка - запутанная строка
//
Функция ЗакрытьСекретПользователя(ВведенныйСекрет, АвторизованныйПользователь, ПризнакКонфиденциальности = 1) Экспорт
	
	Если ПризнакКонфиденциальности = 0 Тогда
		Результат = ВведенныйСекрет;
		
	Иначе
		Если ТипЗнч(АвторизованныйПользователь) = Тип("Строка") Тогда
			ДанныеПользователя = АвторизованныйПользователь;
		Иначе
			ДанныеПользователя = Строка(АвторизованныйПользователь.УникальныйИдентификатор());
		КонецЕсли;	
		
		КлючПользователя = ПолучитьБуферДвоичныхДанныхИзСтроки(Прав(ДанныеПользователя, 6) + "_" + ВведенныйСекрет);
		
		Модуль = КлючПользователя.Размер;
		Случайность	= СтрЗаменить(ДанныеПользователя, "-", "");
		Случайность	= ПолучитьБуферДвоичныхДанныхИзHexСтроки(Случайность);
		
		Перемешать = Новый Массив(Модуль);
		Для Счетчик = 1 По Модуль Цикл
			Перемешать.Установить(Счетчик - 1, Счетчик);
		КонецЦикла;
		
		Для Счетчик = 1 По Модуль Цикл
			ИндексЭлемента = Счетчик % Случайность.Размер;
			ЗначениеЭлемента = Случайность.Получить(ИндексЭлемента) % Модуль;
			НашлиЗначение = Перемешать.Найти(ЗначениеЭлемента);
			НашлиСчетчик = Перемешать.Найти(Счетчик);
			Если НашлиЗначение <> Неопределено
				И НашлиСчетчик <> Неопределено Тогда
				Перемешать.Установить(НашлиСчетчик, ЗначениеЭлемента);
				Перемешать.Установить(НашлиЗначение, Счетчик);
			КонецЕсли;	
		КонецЦикла;
		
		Результат = Новый БуферДвоичныхДанных(КлючПользователя.Размер);
		
		Начало = Случайность.Получить(8) % Модуль;
		
		Ключ1 = Случайность.Получить(6);
		Ключ2 = Случайность.Получить(7);
		
		Для Счетчик = 1 По Модуль Цикл
			СледующееМесто = Перемешать[Начало];
			СледующийБайт = КлючПользователя.Получить(СледующееМесто - 1);
			Результат.Установить(Счетчик - 1, СледующийБайт);
			Начало = (Начало + 1) % Модуль;
		КонецЦикла;
		
		Для Счетчик = 1 По Модуль Цикл
			СледующийБайт = Результат.Получить(Счетчик - 1);
			СледующийБайт = ?(Счетчик % 2 = 1, СледующийБайт + Ключ1, СледующийБайт + Ключ2) % 256;
			Результат.Установить(Счетчик - 1, СледующийБайт);
		КонецЦикла;
		
		Результат = ПолучитьBase64СтрокуИзБуфераДвоичныхДанных(Результат);
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Разбирает тип аутентификационного утверждения.
//
// Параметры:
//  ВариантСпособа - Строка
//  Описание		- Строка
//
// Возвращаемое значение:
//  Структура:
//    * Тип			- ПеречислениеСсылка.СпособыАвторизацииDSS
//    * Идентификатор - ПеречислениеСсылка.СпособыАвторизацииDSS
//						- Строка
//    * Адрес			- Булево
//    * Описание		- Строка 
//
Функция ОписаниеВторичнойАвторизации(ВариантСпособа, Описание = "") Экспорт
	
	ТипыПодтверждения = ТипыВторичнойАвторизации();
	
	Результат = Новый Структура;
	Результат.Вставить("Тип", "");
	Результат.Вставить("Идентификатор", "");
	Результат.Вставить("Адрес", Ложь);
	Результат.Вставить("Описание", "");
	
	Позиция = СтрНайти(ВариантСпособа, "?");
	Если Позиция > 0 Тогда
		Результат.Тип = ТипыПодтверждения[Сред(ВариантСпособа, 1, Позиция - 1)];
		Результат.Идентификатор = ВариантСпособа;
		Результат.Адрес = Истина;
		Результат.Вставить("Описание", Описание);
	Иначе
		Результат.Тип = ТипыПодтверждения[ВариантСпособа];
		Результат.Идентификатор = Результат.Тип;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Разбирает тип аутентификационного утверждения.
//
// Параметры:
//  СписокМетодов		 - Массив из см. ОписаниеВторичнойАвторизации
//  ИдентификаторСпособа - Строка
//                       - ПеречислениеСсылка.СпособыАвторизацииDSS 
//
// Возвращаемое значение:
//   см. ОписаниеВторичнойАвторизации
//
Функция НайтиОписаниеВторичнойАвторизации(СписокМетодов, ИдентификаторСпособа) Экспорт
	
	Результат = ПредопределенныйТипАвторизации(ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.ПустаяСсылка"));
	
	Для Каждого СтрокаМассива Из СписокМетодов Цикл
		Если СтрокаМассива.Идентификатор = ИдентификаторСпособа Тогда
			Результат = СтрокаМассива;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Формирует описание вторичной авторизации при выполнении операции.
//
// Параметры:
//  ИсходныйВариант - Структура
//  ТекущийТип		- ПеречислениеСсылка.СпособыАвторизацииDSS
//
// Возвращаемое значение:
//   см. ОписаниеВторичнойАвторизации
//
Функция ПредопределенныйТипАвторизации(ТекущийТип = Неопределено) Экспорт
	
	Результат = ОписаниеВторичнойАвторизации("");
	Если ЗначениеЗаполнено(ТекущийТип) Тогда
		Результат.Вставить("Тип", ТекущийТип);
	Иначе
		Результат.Вставить("Тип", ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_ОфлайнПодтверждение"));
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Извлекает тип авторизации из входящего описания.
//
// Параметры:
//  ВыбранныйСпособ - ПеречислениеСсылка.СпособыАвторизацииDSS
//                  - Строка
//                  - Структура
//
// Возвращаемое значение:
//  ПеречислениеСсылка.СпособыАвторизацииDSS
//
Функция ПолучитьВторичнуюАвторизацию(ВыбранныйСпособ) Экспорт
	
	Результат = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.ПустаяСсылка");
	
	Если ТипЗнч(ВыбранныйСпособ) = Тип("Структура") Тогда
		Результат = ВыбранныйСпособ.Тип;
	ИначеЕсли ТипЗнч(ВыбранныйСпособ) = Тип("Строка") Тогда
		Результат = ОписаниеВторичнойАвторизации(ВыбранныйСпособ).Тип;
	ИначеЕсли ЗначениеЗаполнено(ВыбранныйСпособ) Тогда
		Результат = ВыбранныйСпособ;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Дополняет список доступных к выбору пользователю способов подтверждения для текущей транзакции.
//
// Параметры:
//  ДанныеПодтверждения - см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//  ТекущийСпособ 		- ПеречислениеСсылка.СпособыАвторизацииDSS
//  ОписаниеСпособа		- Строка
//
Процедура ДополнитьСписокТиповАвторизации(ДанныеПодтверждения, ТекущийСпособ, ОписаниеСпособа = "")
	
	ВторичныйМетод = ОписаниеВторичнойАвторизации(ТекущийСпособ, ОписаниеСпособа);
	Если ДанныеПодтверждения.ДоступныеМетоды.Найти(ВторичныйМетод.Тип) = Неопределено Тогда
		Возврат;
	КонецЕсли;	
	
	Если ВторичныйМетод.Тип = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_DSSSDK") Тогда
		Если ДанныеПодтверждения.ВерсияПодтверждения = 2 И НЕ ЗначениеЗаполнено(ДанныеПодтверждения.ИдентификаторТранзакции) Тогда
			ДанныеПодтверждения.СписокМетодов.Добавить(ВторичныйМетод);
		КонецЕсли;
	Иначе
		ДанныеПодтверждения.СписокМетодов.Добавить(ВторичныйМетод);
	КонецЕсли;
	
КонецПроцедуры

// Проверяет выбранный способ подтверждения операция с помощью мобильного приложения.
//
// Параметры:
//  ВариантАвторизации	- Структура
//                    	- Строка
//                    	- ПеречислениеСсылка.СпособыАвторизацииDSS
//
// Возвращаемое значение:
//  Булево
//
Функция ЭтоМобильноеПриложениеДляПодтверждения(ВариантАвторизации) Экспорт
	
	Результат = Ложь;
	
	Если ТипЗнч(ВариантАвторизации) = Тип("Структура") Тогда
		ТекущийВариант = ВариантАвторизации.Тип;
	ИначеЕсли ТипЗнч(ВариантАвторизации) = Тип("Строка") Тогда
		ТекущийВариант = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_DSSSDK");
	Иначе
		ТекущийВариант = ВариантАвторизации;
	КонецЕсли;
	
	Если ТекущийВариант = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_МобильноеПриложение")
		ИЛИ ТекущийВариант = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_DSSSDK")
		ИЛИ ТекущийВариант = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_AirKeyLite") Тогда
		Результат = Истина;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

#КонецОбласти

#КонецОбласти
